2010-11-16 06:36:50 +05:30
|
|
|
/*
|
2010-12-02 10:03:25 +05:30
|
|
|
* Derived from busybox's udhcpc variant, which in turn was...
|
2010-11-16 06:36:50 +05:30
|
|
|
* Mostly stolen from: dhcpcd - DHCP client daemon
|
|
|
|
* by Yoichi Hariguchi <yoichi@fore.com>
|
|
|
|
* Licensed under GPLv2, see file LICENSE in this source tree.
|
|
|
|
*/
|
|
|
|
#include <unistd.h>
|
2010-12-24 20:02:58 +05:30
|
|
|
#include <stdlib.h>
|
2010-11-16 06:36:50 +05:30
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/if_ether.h>
|
2010-12-24 20:02:58 +05:30
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
2010-11-16 06:36:50 +05:30
|
|
|
#include <sys/time.h>
|
|
|
|
#include <errno.h>
|
2010-12-02 10:03:25 +05:30
|
|
|
#include "arpping.h"
|
2010-12-24 20:02:58 +05:30
|
|
|
#include "clientpacket.h"
|
2010-12-24 20:11:52 +05:30
|
|
|
#include "packet.h"
|
2010-12-24 20:02:58 +05:30
|
|
|
#include "sys.h"
|
|
|
|
#include "script.h"
|
2010-11-16 06:36:50 +05:30
|
|
|
#include "dhcpd.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "strl.h"
|
|
|
|
#include "io.h"
|
|
|
|
|
2010-12-24 20:02:58 +05:30
|
|
|
static struct arpMsg arpreply;
|
|
|
|
static int arpreply_offset;
|
|
|
|
static struct dhcpMessage arp_dhcp_packet;
|
|
|
|
|
2010-12-02 10:03:25 +05:30
|
|
|
/* Returns fd of the arp socket, or -1 on failure. */
|
2010-12-24 20:02:58 +05:30
|
|
|
static int arpping(uint32_t test_nip, const uint8_t *safe_mac,
|
|
|
|
uint32_t from_ip, uint8_t *from_mac, const char *interface)
|
2010-11-16 06:36:50 +05:30
|
|
|
{
|
2010-12-02 10:03:25 +05:30
|
|
|
int arpfd;
|
2010-11-16 06:36:50 +05:30
|
|
|
int opt = 1;
|
|
|
|
struct sockaddr addr; /* for interface name */
|
|
|
|
struct arpMsg arp;
|
|
|
|
|
2010-12-02 10:03:25 +05:30
|
|
|
arpfd = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
|
|
|
|
if (arpfd == -1) {
|
2010-11-16 06:36:50 +05:30
|
|
|
log_warning("arpping: failed to create socket: %s", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-12-02 10:03:25 +05:30
|
|
|
if (setsockopt(arpfd, SOL_SOCKET, SO_BROADCAST,
|
2010-11-16 06:36:50 +05:30
|
|
|
&opt, sizeof opt) == -1) {
|
|
|
|
log_warning("arpping: failed to set broadcast: %s", strerror(errno));
|
2010-12-02 10:03:25 +05:30
|
|
|
close(arpfd);
|
|
|
|
return -1;
|
2010-11-16 06:36:50 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* send arp request */
|
|
|
|
memset(&arp, 0, sizeof arp);
|
|
|
|
memset(arp.h_dest, 0xff, 6); /* MAC DA */
|
|
|
|
memcpy(arp.h_source, from_mac, 6); /* MAC SA */
|
|
|
|
arp.h_proto = htons(ETH_P_ARP); /* protocol type (Ethernet) */
|
|
|
|
arp.htype = htons(ARPHRD_ETHER); /* hardware type */
|
|
|
|
arp.ptype = htons(ETH_P_IP); /* protocol type (ARP message) */
|
|
|
|
arp.hlen = 6; /* hardware address length */
|
|
|
|
arp.plen = 4; /* protocol address length */
|
|
|
|
arp.operation = htons(ARPOP_REQUEST); /* ARP op code */
|
|
|
|
memcpy(arp.sHaddr, from_mac, 6); /* source hardware address */
|
2010-12-02 10:03:25 +05:30
|
|
|
memcpy(arp.sInaddr, &from_ip, sizeof from_ip); /* source IP address */
|
2010-11-16 06:36:50 +05:30
|
|
|
/* tHaddr is zero-filled */ /* target hardware address */
|
|
|
|
memcpy(arp.tInaddr, &test_nip, sizeof test_nip);/* target IP address */
|
|
|
|
|
|
|
|
memset(&addr, 0, sizeof addr);
|
|
|
|
strlcpy(addr.sa_data, interface, sizeof addr.sa_data);
|
2010-12-02 10:03:25 +05:30
|
|
|
if (safe_sendto(arpfd, (const char *)&arp, sizeof arp,
|
2010-11-16 06:36:50 +05:30
|
|
|
0, &addr, sizeof addr) < 0) {
|
|
|
|
log_error("arpping: sendto failed: %s", strerror(errno));
|
2010-12-02 10:03:25 +05:30
|
|
|
close(arpfd);
|
|
|
|
return -1;
|
2010-11-16 06:36:50 +05:30
|
|
|
}
|
2010-12-02 10:03:25 +05:30
|
|
|
return arpfd;
|
2010-11-16 06:36:50 +05:30
|
|
|
}
|
2010-12-24 20:02:58 +05:30
|
|
|
|
|
|
|
void arp_check(struct client_state_t *cs, struct dhcpMessage *packet)
|
|
|
|
{
|
|
|
|
cs->arpPrevState = cs->dhcpState;
|
|
|
|
cs->dhcpState = DS_ARP_CHECK;
|
|
|
|
memcpy(&arp_dhcp_packet, packet, sizeof (struct dhcpMessage));
|
|
|
|
cs->arpFd = arpping(arp_dhcp_packet.yiaddr, NULL, 0,
|
|
|
|
client_config.arp, client_config.interface);
|
|
|
|
epoll_add(cs, cs->arpFd);
|
|
|
|
cs->timeout = 2000;
|
|
|
|
memset(&arpreply, 0, sizeof arpreply);
|
|
|
|
arpreply_offset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void arp_failed(struct client_state_t *cs)
|
|
|
|
{
|
|
|
|
log_line("Offered address is in use: declining.");
|
|
|
|
epoll_del(cs, cs->arpFd);
|
|
|
|
cs->arpFd = -1;
|
|
|
|
send_decline(cs->xid, cs->serverAddr, arp_dhcp_packet.yiaddr);
|
|
|
|
|
|
|
|
if (cs->arpPrevState != DS_REQUESTING)
|
|
|
|
run_script(NULL, SCRIPT_DECONFIG);
|
|
|
|
cs->dhcpState = DS_INIT_SELECTING;
|
|
|
|
cs->requestedIP = 0;
|
|
|
|
cs->timeout = 0;
|
|
|
|
cs->packetNum = 0;
|
2010-12-24 20:11:52 +05:30
|
|
|
change_listen_mode(cs, LM_RAW);
|
2010-12-24 20:02:58 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
void arp_success(struct client_state_t *cs)
|
|
|
|
{
|
|
|
|
struct in_addr temp_addr;
|
|
|
|
|
|
|
|
epoll_del(cs, cs->arpFd);
|
|
|
|
cs->arpFd = -1;
|
|
|
|
|
|
|
|
/* enter bound state */
|
|
|
|
cs->t1 = cs->lease >> 1;
|
|
|
|
/* little fixed point for n * .875 */
|
|
|
|
cs->t2 = (cs->lease * 0x7) >> 3;
|
|
|
|
cs->timeout = cs->t1 * 1000;
|
|
|
|
cs->leaseStartTime = curms();
|
|
|
|
|
|
|
|
temp_addr.s_addr = arp_dhcp_packet.yiaddr;
|
|
|
|
log_line("Lease of %s obtained, lease time %ld.",
|
|
|
|
inet_ntoa(temp_addr), cs->lease);
|
|
|
|
cs->requestedIP = arp_dhcp_packet.yiaddr;
|
|
|
|
run_script(&arp_dhcp_packet,
|
|
|
|
((cs->arpPrevState == DS_RENEWING ||
|
|
|
|
cs->arpPrevState == DS_REBINDING)
|
|
|
|
? SCRIPT_RENEW : SCRIPT_BOUND));
|
|
|
|
|
|
|
|
cs->dhcpState = DS_BOUND;
|
2010-12-24 20:11:52 +05:30
|
|
|
change_listen_mode(cs, LM_NONE);
|
2010-12-24 20:02:58 +05:30
|
|
|
if (client_config.quit_after_lease)
|
|
|
|
exit(EXIT_SUCCESS);
|
|
|
|
if (!client_config.foreground)
|
|
|
|
background();
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef uint32_t aliased_uint32_t __attribute__((__may_alias__));
|
|
|
|
void handle_arp_response(struct client_state_t *cs)
|
|
|
|
{
|
|
|
|
if (arpreply_offset < sizeof arpreply) {
|
|
|
|
int r = safe_read(cs->arpFd, (char *)&arpreply + arpreply_offset,
|
|
|
|
sizeof arpreply - arpreply_offset);
|
|
|
|
if (r < 0) {
|
|
|
|
arp_failed(cs);
|
|
|
|
return;
|
|
|
|
} else
|
|
|
|
arpreply_offset += r;
|
|
|
|
}
|
|
|
|
|
|
|
|
//log3("sHaddr %02x:%02x:%02x:%02x:%02x:%02x",
|
|
|
|
//arp.sHaddr[0], arp.sHaddr[1], arp.sHaddr[2],
|
|
|
|
//arp.sHaddr[3], arp.sHaddr[4], arp.sHaddr[5]);
|
|
|
|
|
|
|
|
if (arpreply_offset >= ARP_MSG_SIZE) {
|
|
|
|
if (arpreply.operation == htons(ARPOP_REPLY)
|
|
|
|
/* don't check: Linux returns invalid tHaddr (fixed in 2.6.24?) */
|
|
|
|
/* && memcmp(arpreply.tHaddr, from_mac, 6) == 0 */
|
|
|
|
&& *(aliased_uint32_t*)arpreply.sInaddr == arp_dhcp_packet.yiaddr)
|
|
|
|
{
|
|
|
|
/* if ARP source MAC matches safe_mac
|
|
|
|
* (which is client's MAC), then it's not a conflict
|
|
|
|
* (client simply already has this IP and replies to ARPs!)
|
|
|
|
*/
|
|
|
|
/* if (memcmp(safe_mac, arpreply.sHaddr, 6) == 0) */
|
|
|
|
/* arp_success(); */
|
|
|
|
arp_failed(cs);
|
|
|
|
} else {
|
|
|
|
memset(&arpreply, 0, sizeof arpreply);
|
|
|
|
arpreply_offset = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|