📄 send_arp.c
字号:
/* $Id: send_arp.c,v 1.13 2004/09/10 02:03:00 alan Exp $ *//* * send_arp * * This program sends out one ARP packet with source/target IP and Ethernet * hardware addresses suuplied by the user. It uses the libnet libary from * Packet Factory (http://www.packetfactory.net/libnet/ ). It has been tested * on Linux, FreeBSD, and on Solaris. * * This inspired by the sample application supplied by Packet Factory. * Matt Soffen * Copyright (C) 2001 Matt Soffen <matt@soffen.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include <portability.h>#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <limits.h>#include <libnet.h>#include <syslog.h>#include <libgen.h>#include <clplumbing/timers.h>#include <clplumbing/cl_signal.h>#ifdef HAVE_LIBNET_1_0_API# define LTYPE struct libnet_link_int#endif#ifdef HAVE_LIBNET_1_1_API# define LTYPE libnet_t#endif#define PIDDIR HA_VARLIBDIR "/" PACKAGE "/rsctmp/send_arp"#define PIDFILE_BASE PIDDIR "/send_arp-"static int send_arp(LTYPE* l, u_long ip, u_char *device, u_char mac[6], u_char *broadcast, u_char *netmask, u_short arptype);static char print_usage[]={ "send_arp: sends out custom ARP packet. packetfactory.net\n" "\tusage: send_arp [-i repeatinterval-ms] [-r repeatcount]" " [-p pidfile] device src_ip_addr src_hw_addr broadcast_ip_addr netmask\n" "\tIf src_hw_addr is \"auto\" then the address of device will be used"};static void convert_macaddr (u_char *macaddr, u_char enet_src[6]);static int get_hw_addr(char *device, u_char mac[6]);int write_pid_file(const char *pidfilename);int create_pid_directory(const char *piddirectory);#define AUTO_MAC_ADDR "auto"#ifndef LIBNET_ERRBUF_SIZE# define LIBNET_ERRBUF_SIZE 256#endifstatic voidbyebye(int nsig){ (void)nsig; /* Avoid an "error exit" log message if we're killed */ exit(0);}intmain(int argc, char *argv[]){ int c = -1; char errbuf[LIBNET_ERRBUF_SIZE]; char* device; char* ipaddr; char* macaddr; char* broadcast; char* netmask; u_long ip; u_char src_mac[6]; LTYPE* l; int repeatcount = 1; int j; long msinterval = 1000; int flag; char pidfilenamebuf[64]; char *pidfilename = NULL; CL_SIGINTERRUPT(SIGTERM, 1); CL_SIGNAL(SIGTERM, byebye); openlog("send_arp", LOG_CONS | LOG_PID, LOG_USER); while ((flag = getopt(argc, argv, "i:r:p:")) != EOF) { switch(flag) { case 'i': msinterval= atol(optarg); break; case 'r': repeatcount= atoi(optarg); break; case 'p': pidfilename= optarg; break; default: fprintf(stderr, "usage: %s\n\n", print_usage); return 1; break; } } if (argc-optind != 5) { fprintf(stderr, "usage: %s\n\n", print_usage); return 1; } /* * argv[optind+1] DEVICE dc0,eth0:0,hme0:0, * argv[optind+2] IP 192.168.195.186 * argv[optind+3] MAC ADDR 00a0cc34a878 * argv[optind+4] BROADCAST 192.168.195.186 * argv[optind+5] NETMASK ffffffffffff */ device = argv[optind]; ipaddr = argv[optind+1]; macaddr = argv[optind+2]; broadcast = argv[optind+3]; netmask = argv[optind+4]; if (!pidfilename) { if (snprintf(pidfilenamebuf, sizeof(pidfilenamebuf), "%s%s", PIDFILE_BASE, ipaddr) >= (int)sizeof(pidfilenamebuf)) { syslog(LOG_INFO, "Pid file truncated"); return EXIT_FAILURE; } pidfilename = pidfilenamebuf; } if(write_pid_file(pidfilename) < 0) { return EXIT_FAILURE; }#if defined(HAVE_LIBNET_1_0_API) if ((ip = libnet_name_resolve(ipaddr, 1)) == -1UL) { syslog(LOG_ERR, "Cannot resolve IP address [%s]", ipaddr); unlink(pidfilename); return EXIT_FAILURE; } l = libnet_open_link_interface(device, errbuf); if (!l) { syslog(LOG_ERR, "libnet_open_link_interface on %s: %s" , device, errbuf); unlink(pidfilename); return EXIT_FAILURE; }#elif defined(HAVE_LIBNET_1_1_API) if ((l=libnet_init(LIBNET_LINK, device, errbuf)) == NULL) { syslog(LOG_ERR, "libnet_init failure on %s", device); unlink(pidfilename); return EXIT_FAILURE; } if ((signed)(ip = libnet_name2addr4(l, ipaddr, 1)) == -1) { syslog(LOG_ERR, "Cannot resolve IP address [%s]", ipaddr); unlink(pidfilename); return EXIT_FAILURE; }#else# error "Must have LIBNET API version defined."#endif if (!strcasecmp(macaddr, AUTO_MAC_ADDR)) { if (get_hw_addr(device, src_mac) < 0) { syslog(LOG_ERR, "Cannot find mac address for %s", device); unlink(pidfilename); return EXIT_FAILURE; } } else { convert_macaddr(macaddr, src_mac); }/* * We need to send both a broadcast ARP request as well as the ARP response we * were already sending. All the interesting research work for this fix was * done by Masaki Hasegawa <masaki-h@pp.iij4u.or.jp> and his colleagues. */ for (j=0; j < repeatcount; ++j) { c = send_arp(l, ip, device, src_mac, broadcast, netmask, ARPOP_REQUEST); if (c < 0) { break; } mssleep(msinterval / 2); c = send_arp(l, ip, device, src_mac, broadcast, netmask, ARPOP_REPLY); if (c < 0) { break; } if (j != repeatcount-1) { mssleep(msinterval / 2); } } unlink(pidfilename); return c < 0 ? EXIT_FAILURE : EXIT_SUCCESS;}voidconvert_macaddr (u_char *macaddr, u_char enet_src[6]){ int i, pos; u_char bits[3]; pos = 0; for (i = 0; i < 6; i++) { /* Inserted to allow old-style MAC addresses */ if (*macaddr == ':') { pos++; } bits[0] = macaddr[pos++]; bits[1] = macaddr[pos++]; bits[2] = '\0'; enet_src[i] = strtol(bits, (char **)NULL, 16); }}#ifdef HAVE_LIBNET_1_0_APIintget_hw_addr(char *device, u_char mac[6]){ struct ether_addr *mac_address; struct libnet_link_int *network; char err_buf[LIBNET_ERRBUF_SIZE]; /* Get around bad prototype for libnet_error() */ char errmess1 [] = "libnet_open_link_interface: %s\n"; char errmess2 [] = "libnet_get_hwaddr: %s\n"; network = libnet_open_link_interface(device, err_buf); if (!network) { libnet_error(LIBNET_ERR_FATAL, errmess1, err_buf); return -1; } mac_address = libnet_get_hwaddr(network, device, err_buf); if (!mac_address) { libnet_error(LIBNET_ERR_FATAL, errmess2, err_buf); return -1; } memcpy(mac, mac_address->ether_addr_octet, 6); return 0;}#endif#ifdef HAVE_LIBNET_1_1_APIintget_hw_addr(char *device, u_char mac[6]){ struct libnet_ether_addr *mac_address; libnet_t *ln; char err_buf[LIBNET_ERRBUF_SIZE]; ln = libnet_init(LIBNET_LINK, device, err_buf); if (!ln) { fprintf(stderr, "libnet_open_link_interface: %s\n", err_buf); return -1; } mac_address = libnet_get_hwaddr(ln); if (!mac_address) { fprintf(stderr, "libnet_get_hwaddr: %s\n", err_buf); return -1; } memcpy(mac, mac_address->ether_addr_octet, 6); return 0;}#endif/* * Notes on send_arp() behaviour. Horms, 15th June 2004 * * 1. Target Hardware Address * (In the ARP portion of the packet) * * a) ARP Reply * * Set to the MAC address we want associated with the VIP, * as per RFC2002 (4.6). * * Previously set to ff:ff:ff:ff:ff:ff * * b) ARP Request * * Set to 00:00:00:00:00:00. According to RFC2002 (4.6) * this value is not used in an ARP request, so the value should * not matter. However, I observed that typically (always?) this value * is set to 00:00:00:00:00:00. It seems harmless enough to follow * this trend. * * Previously set to ff:ff:ff:ff:ff:ff * * 2. Source Hardware Address * (Ethernet Header, not in the ARP portion of the packet) * * Set to the MAC address of the interface that the packet is being * sent to. Actually, due to the way that send_arp is called this would * usually (always?) be the case anyway. Although this value should not * really matter, it seems sensible to set the source address to where * the packet is really coming from. The other obvious choice would be * the MAC address that is being associated for the VIP. Which was the * previous values. Again, these are typically the same thing. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -