Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3155714
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
19 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/tools/send_arp.libnet.c b/tools/send_arp.libnet.c
index d7bca99e3..68facd53e 100644
--- a/tools/send_arp.libnet.c
+++ b/tools/send_arp.libnet.c
@@ -1,764 +1,761 @@
/*
* 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 program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Needs to be defined before any other includes, otherwise some system
* headers do not behave as expected! Major black magic... */
#undef _GNU_SOURCE /* in case it was defined on the command line */
#define _GNU_SOURCE
#include <config.h>
#include <sys/param.h>
#define USE_GNU
#if defined(ANSI_ONLY) && !defined(inline)
# define inline /* nothing */
#endif
#include <limits.h>
#include <libnet.h>
#include <libgen.h>
#include <clplumbing/timers.h>
#include <clplumbing/cl_signal.h>
#include <clplumbing/cl_log.h>
#ifdef HAVE_LIBNET_1_0_API
# define LTYPE struct libnet_link_int
static u_char *mk_packet(u_int32_t ip, u_char *device, u_char *macaddr, u_char *broadcast, u_char *netmask, u_short arptype);
static int send_arp(struct libnet_link_int *l, u_char *device, u_char *buf);
#endif
#ifdef HAVE_LIBNET_1_1_API
# define LTYPE libnet_t
static libnet_t *mk_packet(libnet_t* lntag, u_int32_t ip, u_char *device, u_char macaddr[6], u_char *broadcast, u_char *netmask, u_short arptype);
int send_arp(libnet_t* lntag);
#endif
#define PIDDIR HA_VARRUNDIR "/" PACKAGE
#define PIDFILE_BASE PIDDIR "/send_arp-"
static char print_usage[]={
"send_arp: sends out custom ARP packet.\n"
" usage: send_arp [-i repeatinterval-ms] [-r repeatcount] [-p pidfile] \\\n"
" device src_ip_addr src_hw_addr broadcast_ip_addr netmask\n"
"\n"
" where:\n"
" repeatinterval-ms: timing, in milliseconds of sending arp packets\n"
" For each ARP announcement requested, a pair of ARP packets is sent,\n"
" an ARP request, and an ARP reply. This is because some systems\n"
" ignore one or the other, and this combination gives the greatest\n"
" chance of success.\n"
"\n"
" Each time an ARP is sent, if another ARP will be sent then\n"
" the code sleeps for half of repeatinterval-ms.\n"
"\n"
" repeatcount: how many pairs of ARP packets to send.\n"
" See above for why pairs are sent\n"
"\n"
" pidfile: pid file to use\n"
"\n"
" device: network interface to use\n"
"\n"
" src_ip_addr: source ip address\n"
"\n"
" src_hw_addr: source hardware address.\n"
" If \"auto\" then the address of device\n"
"\n"
" broadcast_ip_addr: ignored\n"
"\n"
" netmask: ignored\n"
};
static const char * SENDARPNAME = "send_arp";
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
#endif
/*
* For use logd, should keep identical with the same const variables defined
* in heartbeat.h.
*/
#define ENV_PREFIX "HA_"
#define KEY_LOGDAEMON "use_logd"
static void
byebye(int nsig)
{
(void)nsig;
/* Avoid an "error exit" log message if we're killed */
exit(0);
}
int
main(int argc, char *argv[])
{
int c = -1;
char errbuf[LIBNET_ERRBUF_SIZE];
char* device;
char* ipaddr;
char* macaddr;
char* broadcast;
char* netmask;
u_int32_t ip;
- u_char src_mac[6];
+ u_char src_mac[6];
int repeatcount = 1;
int j;
long msinterval = 1000;
int flag;
- char pidfilenamebuf[64];
- char *pidfilename = NULL;
+ char *pidfilename = NULL;
+ int pidflen;
struct sigaction act;
#ifdef HAVE_LIBNET_1_0_API
LTYPE* l;
u_char *request, *reply;
#elif defined(HAVE_LIBNET_1_1_API)
LTYPE *request, *reply;
#endif
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags &= ~SA_RESTART; /* redundant - to stress syscalls should fail */
act.sa_handler = byebye;
if ((sigemptyset(&act.sa_mask) < 0) || (sigaction(SIGTERM, &act, NULL) < 0)) {
cl_log(LOG_ERR, "Could not set handler for signal: %s", strerror(errno));
return 1;
}
cl_log_set_entity(SENDARPNAME);
cl_log_enable_stderr(TRUE);
cl_log_set_facility(LOG_USER);
cl_inherit_logging_environment(0);
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, "%s\n\n", print_usage);
return 1;
break;
}
}
if (argc-optind != 5) {
fprintf(stderr, "%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)) {
- cl_log(LOG_INFO, "Pid file truncated");
- return EXIT_FAILURE;
- }
- pidfilename = pidfilenamebuf;
+ pidflen = strlen(PIDFILE_BASE) + strlen(ipaddr);
+ pidfilename = calloc(1, pidflen);
+ snprintf(pidfilename, pidflen, "%s%s",
+ PIDFILE_BASE, ipaddr);
}
if(write_pid_file(pidfilename) < 0) {
return EXIT_FAILURE;
}
if (!strcasecmp(macaddr, AUTO_MAC_ADDR)) {
if (get_hw_addr(device, src_mac) < 0) {
cl_log(LOG_ERR, "Cannot find mac address for %s",
device);
unlink(pidfilename);
return EXIT_FAILURE;
}
}
else {
convert_macaddr((unsigned char *)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.
*/
#if defined(HAVE_LIBNET_1_0_API)
#ifdef ON_DARWIN
if ((ip = libnet_name_resolve((unsigned char*)ipaddr, 1)) == -1UL) {
#else
if ((ip = libnet_name_resolve(ipaddr, 1)) == -1UL) {
#endif
cl_log(LOG_ERR, "Cannot resolve IP address [%s]", ipaddr);
unlink(pidfilename);
return EXIT_FAILURE;
}
l = libnet_open_link_interface(device, errbuf);
if (!l) {
cl_log(LOG_ERR, "libnet_open_link_interface on %s: %s"
, device, errbuf);
unlink(pidfilename);
return EXIT_FAILURE;
}
request = mk_packet(ip, (unsigned char*)device, src_mac
, (unsigned char*)broadcast, (unsigned char*)netmask
, ARPOP_REQUEST);
reply = mk_packet(ip, (unsigned char*)device, src_mac
, (unsigned char *)broadcast
, (unsigned char *)netmask, ARPOP_REPLY);
if (!request || !reply) {
cl_log(LOG_ERR, "could not create packets");
unlink(pidfilename);
return EXIT_FAILURE;
}
for (j=0; j < repeatcount; ++j) {
c = send_arp(l, (unsigned char*)device, request);
if (c < 0) {
break;
}
mssleep(msinterval / 2);
c = send_arp(l, (unsigned char*)device, reply);
if (c < 0) {
break;
}
if (j != repeatcount-1) {
mssleep(msinterval / 2);
}
}
#elif defined(HAVE_LIBNET_1_1_API)
if ((request=libnet_init(LIBNET_LINK, device, errbuf)) == NULL) {
cl_log(LOG_ERR, "libnet_init failure on %s: %s", device, errbuf);
unlink(pidfilename);
return EXIT_FAILURE;
}
if ((reply=libnet_init(LIBNET_LINK, device, errbuf)) == NULL) {
cl_log(LOG_ERR, "libnet_init failure on %s: %s", device, errbuf);
unlink(pidfilename);
return EXIT_FAILURE;
}
if ((signed)(ip = libnet_name2addr4(request, ipaddr, 1)) == -1) {
cl_log(LOG_ERR, "Cannot resolve IP address [%s]", ipaddr);
unlink(pidfilename);
return EXIT_FAILURE;
}
request = mk_packet(request, ip, (unsigned char*)device, src_mac
, (unsigned char*)broadcast, (unsigned char*)netmask
, ARPOP_REQUEST);
reply = mk_packet(reply, ip, (unsigned char*)device, src_mac
, (unsigned char *)broadcast
, (unsigned char *)netmask, ARPOP_REPLY);
if (!request || !reply) {
cl_log(LOG_ERR, "could not create packets");
unlink(pidfilename);
return EXIT_FAILURE;
}
for (j=0; j < repeatcount; ++j) {
c = send_arp(request);
if (c < 0) {
break;
}
mssleep(msinterval / 2);
c = send_arp(reply);
if (c < 0) {
break;
}
if (j != repeatcount-1) {
mssleep(msinterval / 2);
}
}
#else
# error "Must have LIBNET API version defined."
#endif
unlink(pidfilename);
return c < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
void
convert_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((const char *)bits, (char **)NULL, 16);
}
}
#ifdef HAVE_LIBNET_1_0_API
int
get_hw_addr(char *device, u_char mac[6])
{
struct ether_addr *mac_address;
struct libnet_link_int *network;
char err_buf[LIBNET_ERRBUF_SIZE];
network = libnet_open_link_interface(device, err_buf);
if (!network) {
fprintf(stderr, "libnet_open_link_interface: %s\n", err_buf);
return -1;
}
mac_address = libnet_get_hwaddr(network, device, err_buf);
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
#ifdef HAVE_LIBNET_1_1_API
int
get_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.
*
* Previously set to MAC address being associated with the VIP
*/
#ifdef HAVE_LIBNET_1_0_API
u_char *
mk_packet(u_int32_t ip, u_char *device, u_char *macaddr, u_char *broadcast, u_char *netmask, u_short arptype)
{
u_char *buf;
u_char *target_mac;
u_char device_mac[6];
u_char bcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
u_char zero_mac[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
if (libnet_init_packet(LIBNET_ARP_H + LIBNET_ETH_H, &buf) == -1) {
cl_log(LOG_ERR, "libnet_init_packet memory:");
return NULL;
}
/* Convert ASCII Mac Address to 6 Hex Digits. */
/* Ethernet header */
if (get_hw_addr((char*)device, device_mac) < 0) {
cl_log(LOG_ERR, "Cannot find mac address for %s",
device);
return NULL;
}
if (libnet_build_ethernet(bcast_mac, device_mac, ETHERTYPE_ARP, NULL, 0
, buf) == -1) {
cl_log(LOG_ERR, "libnet_build_ethernet failed:");
libnet_destroy_packet(&buf);
return NULL;
}
if (arptype == ARPOP_REQUEST) {
target_mac = zero_mac;
}
else if (arptype == ARPOP_REPLY) {
target_mac = macaddr;
}
else {
cl_log(LOG_ERR, "unknown arptype");
return NULL;
}
/*
* ARP header
*/
if (libnet_build_arp(ARPHRD_ETHER, /* Hardware address type */
ETHERTYPE_IP, /* Protocol address type */
6, /* Hardware address length */
4, /* Protocol address length */
arptype, /* ARP operation */
macaddr, /* Source hardware addr */
(u_char *)&ip, /* Target hardware addr */
target_mac, /* Destination hw addr */
(u_char *)&ip, /* Target protocol address */
NULL, /* Payload */
0, /* Payload length */
buf + LIBNET_ETH_H) == -1) {
cl_log(LOG_ERR, "libnet_build_arp failed:");
libnet_destroy_packet(&buf);
return NULL;
}
return buf;
}
#endif /* HAVE_LIBNET_1_0_API */
#ifdef HAVE_LIBNET_1_1_API
libnet_t*
mk_packet(libnet_t* lntag, u_int32_t ip, u_char *device, u_char macaddr[6], u_char *broadcast, u_char *netmask, u_short arptype)
{
u_char *target_mac;
u_char device_mac[6];
u_char bcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
u_char zero_mac[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
if (arptype == ARPOP_REQUEST) {
target_mac = zero_mac;
}
else if (arptype == ARPOP_REPLY) {
target_mac = macaddr;
}
else {
cl_log(LOG_ERR, "unkonwn arptype:");
return NULL;
}
/*
* ARP header
*/
if (libnet_build_arp(ARPHRD_ETHER, /* hardware address type */
ETHERTYPE_IP, /* protocol address type */
6, /* Hardware address length */
4, /* protocol address length */
arptype, /* ARP operation type */
macaddr, /* sender Hardware address */
(u_int8_t *)&ip, /* sender protocol address */
target_mac, /* target hardware address */
(u_int8_t *)&ip, /* target protocol address */
NULL, /* Payload */
0, /* Length of payload */
lntag, /* libnet context pointer */
0 /* packet id */
) == -1 ) {
cl_log(LOG_ERR, "libnet_build_arp failed:");
return NULL;
}
/* Ethernet header */
if (get_hw_addr((char *)device, device_mac) < 0) {
cl_log(LOG_ERR, "Cannot find mac address for %s",
device);
return NULL;
}
if (libnet_build_ethernet(bcast_mac, device_mac, ETHERTYPE_ARP, NULL, 0
, lntag, 0) == -1 ) {
cl_log(LOG_ERR, "libnet_build_ethernet failed:");
return NULL;
}
return lntag;
}
#endif /* HAVE_LIBNET_1_1_API */
#ifdef HAVE_LIBNET_1_0_API
int
send_arp(struct libnet_link_int *l, u_char *device, u_char *buf)
{
int n;
n = libnet_write_link_layer(l, (char*)device, buf, LIBNET_ARP_H + LIBNET_ETH_H);
if (n == -1) {
cl_log(LOG_ERR, "libnet_write_link_layer failed");
}
return (n);
}
#endif /* HAVE_LIBNET_1_0_API */
#ifdef HAVE_LIBNET_1_1_API
int
send_arp(libnet_t* lntag)
{
int n;
n = libnet_write(lntag);
if (n == -1) {
cl_log(LOG_ERR, "libnet_write failed");
}
return (n);
}
#endif /* HAVE_LIBNET_1_1_API */
int
create_pid_directory(const char *pidfilename)
{
int status;
struct stat stat_buf;
char *pidfilename_cpy;
char *dir;
pidfilename_cpy = strdup(pidfilename);
if (!pidfilename_cpy) {
cl_log(LOG_INFO, "Memory allocation failure: %s\n",
strerror(errno));
return -1;
}
dir = dirname(pidfilename_cpy);
status = stat(dir, &stat_buf);
if (status < 0 && errno != ENOENT && errno != ENOTDIR) {
cl_log(LOG_INFO, "Could not stat pid-file directory "
"[%s]: %s", dir, strerror(errno));
free(pidfilename_cpy);
return -1;
}
if (status >= 0) {
if (S_ISDIR(stat_buf.st_mode)) {
return 0;
}
cl_log(LOG_INFO, "Pid-File directory exists but is "
"not a directory [%s]", dir);
free(pidfilename_cpy);
return -1;
}
if (mkdir(dir, S_IRUSR|S_IWUSR|S_IXUSR | S_IRGRP|S_IXGRP) < 0) {
/* Did someone else make it while we were trying ? */
if (errno == EEXIST && stat(dir, &stat_buf) >= 0
&& S_ISDIR(stat_buf.st_mode)) {
return 0;
}
cl_log(LOG_INFO, "Could not create pid-file directory "
"[%s]: %s", dir, strerror(errno));
free(pidfilename_cpy);
return -1;
}
free(pidfilename_cpy);
return 0;
}
int
write_pid_file(const char *pidfilename)
{
int pidfilefd;
char pidbuf[11];
unsigned long pid;
ssize_t bytes;
if (*pidfilename != '/') {
cl_log(LOG_INFO, "Invalid pid-file name, must begin with a "
"'/' [%s]\n", pidfilename);
return -1;
}
if (create_pid_directory(pidfilename) < 0) {
return -1;
}
while (1) {
pidfilefd = open(pidfilename, O_CREAT|O_EXCL|O_RDWR,
S_IRUSR|S_IWUSR);
if (pidfilefd < 0) {
if (errno != EEXIST) { /* Old PID file */
cl_log(LOG_INFO, "Could not open pid-file "
"[%s]: %s", pidfilename,
strerror(errno));
return -1;
}
}
else {
break;
}
pidfilefd = open(pidfilename, O_RDONLY, S_IRUSR|S_IWUSR);
if (pidfilefd < 0) {
cl_log(LOG_INFO, "Could not open pid-file "
"[%s]: %s", pidfilename,
strerror(errno));
return -1;
}
while (1) {
bytes = read(pidfilefd, pidbuf, sizeof(pidbuf)-1);
if (bytes < 0) {
if (errno == EINTR) {
continue;
}
cl_log(LOG_INFO, "Could not read pid-file "
"[%s]: %s", pidfilename,
strerror(errno));
return -1;
}
pidbuf[bytes] = '\0';
break;
}
if(unlink(pidfilename) < 0) {
cl_log(LOG_INFO, "Could not delete pid-file "
"[%s]: %s", pidfilename,
strerror(errno));
return -1;
}
if (!bytes) {
cl_log(LOG_INFO, "Invalid pid in pid-file "
"[%s]: %s", pidfilename,
strerror(errno));
return -1;
}
close(pidfilefd);
pid = strtoul(pidbuf, NULL, 10);
if (pid == ULONG_MAX && errno == ERANGE) {
cl_log(LOG_INFO, "Invalid pid in pid-file "
"[%s]: %s", pidfilename,
strerror(errno));
return -1;
}
if (kill(pid, SIGKILL) < 0 && errno != ESRCH) {
cl_log(LOG_INFO, "Error killing old process [%lu] "
"from pid-file [%s]: %s", pid,
pidfilename, strerror(errno));
return -1;
}
cl_log(LOG_INFO, "Killed old send_arp process [%lu]\n",
pid);
}
if (snprintf(pidbuf, sizeof(pidbuf), "%u"
, getpid()) >= (int)sizeof(pidbuf)) {
cl_log(LOG_INFO, "Pid too long for buffer [%u]", getpid());
return -1;
}
while (1) {
bytes = write(pidfilefd, pidbuf, strlen(pidbuf));
if (bytes != (ssize_t)strlen(pidbuf)) {
if (bytes < 0 && errno == EINTR) {
continue;
}
cl_log(LOG_INFO, "Could not write pid-file "
"[%s]: %s", pidfilename,
strerror(errno));
return -1;
}
break;
}
close(pidfilefd);
return 0;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Feb 27, 12:40 AM (17 h, 31 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1465960
Default Alt Text
(19 KB)
Attached To
Mode
rR Resource Agents
Attached
Detach File
Event Timeline
Log In to Comment