Commit 2445b209 authored by wangyongshou's avatar wangyongshou

init arp

parent 4c4536d7
Pipeline #33 canceled with stages
EXEFILE ?= setuniarp
all:
rm -rf $(EXEFILE)
gcc -o $(EXEFILE) setuniarp.c -lpcap -g
#!/bin/bash
base=$(cd $(dirname $0); pwd)
UEIP=192.169.0.0
PREFIX=24
INTER=enp3s0f0
MAC=00:1b:21:cb:94:a8
VPPEXPORT=192.168.30.10
echo "$base"
echo "$UEIP"
echo "$PREFIX"
echo "$INTER"
echo "$MAC"
echo "$VPPEXPORT"
#./setuniarp vppout de:dd:91:00:f6:42 192.169.0.0/24
echo "$base"/setuniarp $INTER $MAC "$UEIP/$PREFIX" $VPPEXPORT
"$base"/setuniarp $INTER $MAC "$UEIP/$PREFIX" $VPPEXPORT
#!/bin/bash
rm -rf setuniarp
make
//#define DEBUG
#include <pcap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#ifndef __linux__
#include <ifaddrs.h>
#include <net/if_dl.h>
#endif
/* ARP Header */
#define ARP_REQUEST 1 /* ARP Request */
#define ARP_REPLY 2 /* ARP Reply */
#ifndef PROGRAM_NAME
# define PROGRAM_NAME "setuniarp"
#endif
struct cidr {
struct cidr *next;
struct in_addr addr; /* addr and mask are host order */
struct in_addr mask;
};
struct cidr *targets = NULL, *excludes = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
u_char target_mac[ETHER_ADDR_LEN]; /* target MAC address */
char *ifname;
static char *pidfile = NULL;
static pcap_t *pc;
long unsigned int g_vpp_export_ip = 0;
char* cidr_to_str(struct cidr *a) {
//char buf[64];
char buf[1024];
char *res = NULL;
int res_alloc, res_len;
int len;
while (a) {
if (a->mask.s_addr == INADDR_NONE) {
len = snprintf(buf, sizeof buf, "dst host %s", inet_ntoa(a->addr));
} else {
//len = snprintf(buf, sizeof buf, "( dst net %s mask ", inet_ntoa(a->addr));
len = snprintf(buf, sizeof buf, "( src net %s mask ", inet_ntoa(a->addr));
len += snprintf(buf + len, sizeof buf - len, "%s )", inet_ntoa(a->mask));
//len += snprintf(buf + len, sizeof buf - len, " or ( dst net %s mask ", inet_ntoa(a->addr));
//len += snprintf(buf + len, sizeof buf - len, "%s)", inet_ntoa(a->mask));
//len += snprintf(buf + len, sizeof buf - len, "%s", inet_ntoa(a->mask));
}
if (!res) {
res_alloc = 1024;
res = malloc(res_alloc);
strncpy(res, buf, res_alloc);
res_len = len;
} else {
if (res_len + len + 5 > res_alloc) {
res_alloc *= 2;
res = realloc(res, res_alloc);
}
strncat(res, " or ", res_alloc - res_len - 1);
res_len += 4;
strncat(res, buf, res_alloc - res_len - 1);
res_len += len;
}
a = a->next;
}
return res;
}
pcap_t *
open_pcap(char *ifname, char *filter_str) {
pcap_t *pc = NULL;
struct bpf_program filter;
/* Set up PCAP */
if ((pc = pcap_open_live(ifname, 128, 0, 512, errbuf))==NULL){
fprintf(stderr, "pcap_open_live failed: %s\n", errbuf);
exit(1);
}
/* Compiles the filter expression */
printf("filter_str:%s\n", filter_str);
if (pcap_compile(pc, &filter, filter_str, 1, PCAP_NETMASK_UNKNOWN) == -1){
//if (pcap_compile(pc, &filter, "arp", 1, PCAP_NETMASK_UNKNOWN) == -1){
fprintf(stderr, "pcap_compile failed: %s\n", pcap_geterr(pc) );
exit(1);
}
/* Set filter program */
if (pcap_setfilter(pc, &filter) == -1){
fprintf(stderr, "pcap_setfilter failed: %s\n", pcap_geterr(pc));
exit(1);
}
pcap_freecode(&filter);
return pc;
}
int set_arp_item(uint32_t ip, unsigned char *mac)
{
#define ARP_SET_BY_IOCTL
#ifdef ARP_SET_BY_IOCTL
if(ip != g_vpp_export_ip)
{
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0 ){
return 10;
}
struct in_addr inaddr;
inaddr.s_addr=ip;
struct arpreq req;
memset(&req, 0, sizeof(req));
req.arp_ha.sa_family = ARPHRD_ETHER;
memcpy(&req.arp_ha.sa_data, mac, 6);
req.arp_flags = ATF_PERM | ATF_COM;
strncpy(req.arp_dev, ifname, strlen(ifname));
struct sockaddr_in *in = (struct sockaddr_in*) &req.arp_pa;
in->sin_addr.s_addr = ip; ////htonl(ip);
in->sin_family = AF_INET;
if(ioctl(fd, SIOCSARP, &req) < 0) {
close(fd);
return 20;
}
close(fd);
return 0;
}
#else
char *ip_addr_char = (char *)(&ip);
char *target_mac = (char *)mac;
char cmd_buf[256];
sprintf(cmd_buf,"arp -s %d.%d.%d.%d %02x:%02x:%02x:%02x:%02x:%02x -i %s", \
ip_addr_char[0],ip_addr_char[1],ip_addr_char[2],ip_addr_char[3], \
target_mac[0]&0xff,target_mac[1]&0xff,target_mac[2]&0xff,target_mac[3]&0xff,target_mac[4]&0xff,target_mac[5]&0xff,ifname);
# ifdef DEBUG
fprintf(stdout,"cmd_buf = %s.\n",cmd_buf);
# endif
system(cmd_buf);
#endif
}
void
gen_arpreply(u_char *buf) {
struct ether_arp *arp;
struct in_addr ipbuf;
char *ip_addr_char = (char *)(&ipbuf);
int ret;
/* set ethernet dst/src address */
memcpy(buf, buf+ETHER_ADDR_LEN, ETHER_ADDR_LEN);
memcpy(buf+ETHER_ADDR_LEN, target_mac, ETHER_ADDR_LEN);
/* set result of ARP request */
arp = (struct ether_arp *)(buf + ETHER_HDR_LEN);
memcpy((char*) &ipbuf, arp->arp_tpa, sizeof(ipbuf)); /* save protocol addr */
memcpy(arp->arp_tha, arp->arp_sha, sizeof(arp->arp_tha)); /* set target hard addr */
memcpy(arp->arp_tpa, arp->arp_spa, sizeof(arp->arp_tpa)); /* set target proto addr */
memcpy(arp->arp_spa, (char *)&ipbuf, sizeof(ipbuf)); /* set source protocol addr */
memcpy(arp->arp_sha, target_mac, ETHER_ADDR_LEN); /* set source hard addr */
arp->arp_op = htons(ARPOP_REPLY);
if(ret=set_arp_item(ipbuf.s_addr , target_mac)){
# ifdef DEBUG
fprintf(stdout,"Error occured while setting %d.%d.%d.%d to %02x:%02x:%02x:%02x:%02x:%02x (ret=%d)\n", \
ip_addr_char[0],ip_addr_char[1],ip_addr_char[2],ip_addr_char[3], \
target_mac[0],target_mac[1],target_mac[2],target_mac[3],target_mac[4],target_mac[5],ret);
# endif
//perror("set arp");
}else{
# ifdef DEBUG
fprintf(stdout,"%d.%d.%d.%d => %02x:%02x:%02x:%02x:%02x:%02x\n", \
ip_addr_char[0],ip_addr_char[1],ip_addr_char[2],ip_addr_char[3], \
target_mac[0],target_mac[1],target_mac[2],target_mac[3],target_mac[4],target_mac[5]);
# endif
}
}
void
cleanup(int sig){
if (pidfile != NULL)
unlink(pidfile);
pcap_breakloop(pc);
pcap_close(pc);
exit(0);
}
void
process_arp(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *packet) {
#ifdef DEBUG
fprintf(stdout,"[process_arp] - \n");
#endif
gen_arpreply((u_char *)packet);
#if 1 //broadcast one reply packet
pcap_inject((pcap_t *)user, packet, pkthdr->len);
#endif
}
int
setmac(char *addr, char *ifname){
u_int m0, m1, m2, m3, m4, m5;
if (!strcmp (addr, "auto")) {
#ifdef __linux__
int fd;
struct ifreq ifr;
if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
return -1;
}
strncpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
perror("ioctl(SIOCGIFHWADDR)");
return -1;
}
memcpy(target_mac, ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
return 0;
#else
struct ifaddrs *ifas, *ifa;
getifaddrs (&ifas);
for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
#define SDL ((struct sockaddr_dl *)ifa->ifa_addr)
if (strcmp (ifa->ifa_name, ifname)
|| SDL->sdl_family != AF_LINK
|| SDL->sdl_alen != ETHER_ADDR_LEN)
continue;
memcpy (target_mac, SDL->sdl_data + SDL->sdl_nlen, ETHER_ADDR_LEN);
return 0;
}
#endif
fprintf(stderr, "%s: not found\n", ifname);
return -1;
} else if (!strncmp (addr, "vhid:", 4)) {
/*
* Virtual router mac address
* CARP address format: 00:00:5e:00:01:<VHID>
*/
char *vhid = addr + 5;
if (!*vhid)
return(-1);
m0 = 0;
m1 = 0;
m2 = 0x5e;
m3 = 0;
m4 = 1;
m5 = atoi(vhid);
} else if (sscanf(addr, "%x:%x:%x:%x:%x:%x", &m0, &m1, &m2, &m3, &m4, &m5) < 6) {
fprintf(stderr, "invalid MAC address: %s", addr);
return(-1);
}
target_mac[0] = (u_char )m0;
target_mac[1] = (u_char )m1;
target_mac[2] = (u_char )m2;
target_mac[3] = (u_char )m3;
target_mac[4] = (u_char )m4;
target_mac[5] = (u_char )m5;
return(0);
}
int
atoip(char *buf, u_int32_t *ip_addr){
u_int i0, i1, i2, i3;
if (sscanf(buf, "%u.%u.%u.%u", &i0, &i1, &i2, &i3) == 4){
*ip_addr = (i0 << 24) + (i1 << 16) + (i2 << 8) + i3;
return(0);
}
if (sscanf(buf, "0x%lx", (unsigned long *) ip_addr) == 1)
return(0);
return(-1);
}
void
usage(){
fprintf(stderr,"Usage: \n\t%s [-p PIDFILE] interface macaddress [-]ipaddrress/mask...\n",PROGRAM_NAME);
fprintf(stderr,"Example:\n\t%s eth0 00:11:22:33:44:55 100.1.1.0/24\n",PROGRAM_NAME);
exit(-1);
}
void handle(int sig)
{
if(sig == SIGINT)
{
fprintf(stdout, "pcap_close %p, sleep 1\n", pc);
pcap_close(pc);
sleep(1);
exit(0);
}
}
int
main(int argc, char **argv){
signal(SIGINT,handle);
int pidf, opt;
char *filter, *targets_filter, *excludes_filter;
struct cidr **targets_tail = &targets, **excludes_tail = &excludes;
struct sigaction act;
#define APPEND(LIST,ADDR,MASK) \
do { \
*(LIST ## _tail) = malloc(sizeof (struct cidr)); \
(*(LIST ## _tail))->addr.s_addr = htonl(ADDR); \
(*(LIST ## _tail))->mask.s_addr = htonl(MASK); \
(*(LIST ## _tail))->next = NULL; \
(LIST ## _tail) = &(*(LIST ## _tail))->next; \
} while (0)
while ((opt = getopt(argc, argv, "p:")) != -1) {
switch (opt) {
case 'p':
pidfile = optarg;
break;
case '?':
usage();
}
}
if (pidfile == NULL) {
argv++;
argc--;
} else {
argv += 4;
argc -= 4;
}
if (argc < 4)
usage();
ifname = argv[0];
if (setmac(argv[1], ifname)) {
exit(1);
}
argv += 2; argc -= 2;
while (argc > 0) {
if(argc == 1)
{
g_vpp_export_ip = inet_addr(*argv);
break;
}
u_int32_t addr, mask = ~0;
char *slash = strchr (*argv, '/');
int exclude = 0;
if (**argv == '-') {
(*argv)++;
exclude = 1;
}
if (slash != NULL)
*(slash++) = '\0';
if (atoip (*argv, &addr))
usage();
if (slash != NULL) {
char *end;
u_int32_t len = strtol (slash, &end, 10);
if (*end == '\0')
mask <<= (32 - len);
else if (atoip (slash, &mask))
usage();
}
if (exclude)
APPEND(excludes, addr, mask);
else
APPEND(targets, addr, mask);
argv++, argc--;
}
#ifdef DEBUG
#define SHOW(LIST) \
do { \
struct cidr *t; \
fprintf (stderr, #LIST ":\n"); \
for (t = LIST; t; t = t->next) { \
fprintf (stderr, " %s", inet_ntoa (t->addr)); \
fprintf (stderr, "/%s\n", inet_ntoa (t->mask)); \
} \
} while (0)
SHOW(targets);
SHOW(excludes);
////exit (0);
#endif
targets_filter = cidr_to_str(targets);
excludes_filter = cidr_to_str(excludes);
//fprintf(stdout, "targets_filter:%s\n",targets_filter);
//fprintf(stdout, "excludes_filter:%s\n",excludes_filter);
#if 0
#define TMPL_FILTER "arp and (%s)"
#define TMPL_FILTER "arp[2:2] == 0x0800 " /* Protocol: IPv4 */ \
"and arp[4] == 6 " /* Hw addr length: 6 */ \
"and arp[5] == 4 " /* Proto addr length: 4 */ \
"and arp[6:2] == 1 " /* Operation: Request */ \
"and (%s)"
#endif
#define TMPL_FILTER "arp[2:2] == 0x0800 " /* Protocol: IPv4 */ \
"and arp[4] == 6 " /* Hw addr length: 6 */ \
"and arp[5] == 4 " /* Proto addr length: 4 */ \
"and arp[6:2] == 1 " /* Operation: Request */
#define EXCL_FILTER TMPL_FILTER " and not (%s)"
if (excludes_filter == NULL)
{
asprintf (&filter, TMPL_FILTER, targets_filter);
}
else
{
asprintf (&filter, EXCL_FILTER, targets_filter, excludes_filter);
}
#ifdef DEBUG
fprintf(stderr, "Filter on %s: %s\n", ifname, filter);
#endif
//fprintf(stdout, "filter:%s\n",filter);
if ((pc = open_pcap(ifname, filter)) < 0){
fprintf(stderr,"open_pcap");
exit(1);
}
free(filter);
if (pidfile != NULL) {
pidf = open(pidfile, O_RDWR | O_CREAT | O_FSYNC, 0600);
if (pidf > 0) {
ftruncate(pidf, 0);
dprintf(pidf, "%u\n", getpid());
close(pidf);
memset(&act, 0, sizeof(act));
act.sa_handler = cleanup;
sigaction(SIGINT, &act, NULL);
sigaction(SIGTERM, &act, NULL);
}
}
#ifdef DEBUG
fprintf(stdout,"[Begin loop]:\n");
#endif
pcap_loop(pc, 0, process_arp, (u_char*)pc);
//pcap_loop(pc, -1, process_arp, (u_char*)pc);
pcap_close(pc);
exit(1);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment