Rewrite the ARP ping code to properly use modern interfaces. In detail:

- Use AF_PACKET and SOCK_RAW rather than the decade-deprecated
  SOCK_PACKET interface.
- Separate out socket creation code into a subfunction.
- Use C99 initializers for packet and address structures.
- Cosmetic cleanups.
This commit is contained in:
Nicholas J. Kain 2011-06-25 13:02:56 -04:00
parent 8f5eb7e921
commit c37d815754

View File

@ -3,10 +3,6 @@
* *
* Copyright 2010-2011 Nicholas J. Kain <njkain@gmail.com> * Copyright 2010-2011 Nicholas J. Kain <njkain@gmail.com>
* *
* Originally derived from busybox's udhcpc variant, which in turn was...
* Mostly stolen from: dhcpcd - DHCP client daemon
* by Yoichi Hariguchi <yoichi@fore.com>
*
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -30,6 +26,7 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/time.h> #include <sys/time.h>
#include <linux/if_packet.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include "arp.h" #include "arp.h"
@ -38,7 +35,6 @@
#include "ifchange.h" #include "ifchange.h"
#include "leasefile.h" #include "leasefile.h"
#include "log.h" #include "log.h"
#include "strl.h"
#include "io.h" #include "io.h"
#define ARP_MSG_SIZE 0x2a #define ARP_MSG_SIZE 0x2a
@ -49,33 +45,18 @@ static int arpreply_offset;
static struct dhcpMessage arp_dhcp_packet; static struct dhcpMessage arp_dhcp_packet;
static int arp_packet_num; static int arp_packet_num;
static int arp_close_fd(struct client_state_t *cs) static int arp_open_fd(struct client_state_t *cs)
{ {
if (cs->arpFd != -1) {
epoll_del(cs, cs->arpFd);
close(cs->arpFd);
cs->arpFd = -1;
return 1;
}
return 0;
}
/* Returns 0 on success, -1 on failure. */
static int arpping(struct client_state_t *cs, uint32_t test_ip)
{
int opt = 1;
struct sockaddr addr; /* for interface name */
struct arpMsg arp;
if (cs->arpFd == -1) { if (cs->arpFd == -1) {
int arpfd = socket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)); int arpfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
if (arpfd == -1) { if (arpfd == -1) {
log_error("arp: failed to create socket: %s", strerror(errno)); log_error("arp: failed to create socket: %s", strerror(errno));
return -1; return -1;
} }
int opt = 1;
if (setsockopt(arpfd, SOL_SOCKET, SO_BROADCAST, if (setsockopt(arpfd, SOL_SOCKET, SO_BROADCAST,
&opt, sizeof opt) == -1) { &opt, sizeof opt) == -1) {
log_error("arp: failed to set broadcast: %s", strerror(errno)); log_error("arp: failed to set broadcast: %s", strerror(errno));
close(arpfd); close(arpfd);
return -1; return -1;
@ -88,26 +69,48 @@ static int arpping(struct client_state_t *cs, uint32_t test_ip)
cs->arpFd = arpfd; cs->arpFd = arpfd;
epoll_add(cs, arpfd); epoll_add(cs, arpfd);
} }
return 0;
}
/* send arp request */ static int arp_close_fd(struct client_state_t *cs)
memset(&arp, 0, sizeof arp); {
memset(arp.h_dest, 0xff, 6); /* MAC DA */ if (cs->arpFd != -1) {
memcpy(arp.h_source, client_config.arp, 6); /* MAC SA */ epoll_del(cs, cs->arpFd);
arp.h_proto = htons(ETH_P_ARP); /* protocol type (Ethernet) */ close(cs->arpFd);
arp.htype = htons(ARPHRD_ETHER); /* hardware type */ cs->arpFd = -1;
arp.ptype = htons(ETH_P_IP); /* protocol type (ARP message) */ return 1;
arp.hlen = 6; /* hardware address length */ }
arp.plen = 4; /* protocol address length */ return 0;
arp.operation = htons(ARPOP_REQUEST); /* ARP op code */ }
memcpy(arp.smac, client_config.arp, 6); /* source hardware address */
memset(arp.sip4, 0, sizeof arp.sip4); /* source IP address */ // Returns 0 on success, -1 on failure.
/* dmac is zero-filled */ /* target hardware address */ static int arpping(struct client_state_t *cs, uint32_t test_ip)
memcpy(arp.dip4, &test_ip, sizeof test_ip); /* target IP address */ {
if (arp_open_fd(cs) == -1)
return -1;
struct arpMsg arp = {
.h_proto = htons(ETH_P_ARP),
.htype = htons(ARPHRD_ETHER),
.ptype = htons(ETH_P_IP),
.hlen = 6,
.plen = 4,
.operation = htons(ARPOP_REQUEST),
};
memset(arp.h_dest, 0xff, 6);
memcpy(arp.h_source, client_config.arp, 6);
memcpy(arp.smac, client_config.arp, 6);
memcpy(arp.dip4, &test_ip, sizeof test_ip);
struct sockaddr_ll addr = {
.sll_family = AF_PACKET,
.sll_ifindex = client_config.ifindex,
.sll_halen = 6,
};
memcpy(addr.sll_addr, client_config.arp, 6);
memset(&addr, 0, sizeof addr);
strlcpy(addr.sa_data, client_config.interface, sizeof addr.sa_data);
if (safe_sendto(cs->arpFd, (const char *)&arp, sizeof arp, if (safe_sendto(cs->arpFd, (const char *)&arp, sizeof arp,
0, &addr, sizeof addr) < 0) { 0, (struct sockaddr *)&addr, sizeof addr) < 0) {
log_error("arp: sendto failed: %s", strerror(errno)); log_error("arp: sendto failed: %s", strerror(errno));
arp_close_fd(cs); arp_close_fd(cs);
return -1; return -1;
@ -195,10 +198,8 @@ void arp_success(struct client_state_t *cs)
arp_close_fd(cs); arp_close_fd(cs);
/* enter bound state */
cs->t1 = cs->lease >> 1; cs->t1 = cs->lease >> 1;
/* little fixed point for n * .875 */ cs->t2 = (cs->lease * 0x7) >> 3; // T2 = lease * 0.875
cs->t2 = (cs->lease * 0x7) >> 3;
cs->timeout = cs->t1 * 1000; cs->timeout = cs->t1 * 1000;
cs->leaseStartTime = curms(); cs->leaseStartTime = curms();