1ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* Copyright (c) 2006 Simon Kelley 2ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 3ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat This program is free software; you can redistribute it and/or modify 4ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat it under the terms of the GNU General Public License as published by 5ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat the Free Software Foundation; version 2 dated June, 1991. 6ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 7ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat This program is distributed in the hope that it will be useful, 8ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat but WITHOUT ANY WARRANTY; without even the implied warranty of 9ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat GNU General Public License for more details. 11ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat*/ 12ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 13ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* dhcp_release <interface> <address> <MAC address> <client_id> 14ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat MUST be run as root - will fail otherwise. */ 15ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 16ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat/* Send a DHCPRELEASE message via the specified interface 17ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat to tell the local DHCP server to delete a particular lease. 18ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 19ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat The interface argument is the interface in which a DHCP 20ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat request _would_ be received if it was coming from the client, 21ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat rather than being faked up here. 22ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 23ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat The address argument is a dotted-quad IP addresses and mandatory. 24ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 25ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat The MAC address is colon separated hex, and is mandatory. It may be 26ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat prefixed by an address-type byte followed by -, eg 27ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 28ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 10-11:22:33:44:55:66 29ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 30ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat but if the address-type byte is missing it is assumed to be 1, the type 31ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for ethernet. This encoding is the one used in dnsmasq lease files. 32ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 33ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat The client-id is optional. If it is "*" then it treated as being missing. 34ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat*/ 35ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 36ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <sys/types.h> 37ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <netinet/in.h> 38ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <net/if.h> 39ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <arpa/inet.h> 40ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <sys/socket.h> 41ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <unistd.h> 42ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <stdio.h> 43ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <string.h> 44ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <stdlib.h> 45ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <net/if_arp.h> 46ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <sys/ioctl.h> 47ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <linux/types.h> 48ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <linux/netlink.h> 49ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <linux/rtnetlink.h> 50ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#include <errno.h> 51ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 52ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define DHCP_CHADDR_MAX 16 53ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define BOOTREQUEST 1 54ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define DHCP_COOKIE 0x63825363 55ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OPTION_SERVER_IDENTIFIER 54 56ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OPTION_CLIENT_ID 61 57ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OPTION_MESSAGE_TYPE 53 58ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define OPTION_END 255 59ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define DHCPRELEASE 7 60ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat#define DHCP_SERVER_PORT 67 61ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 62ffd68729961f7383f2e35494a03ccdef20f86c98San Mehattypedef unsigned char u8; 63ffd68729961f7383f2e35494a03ccdef20f86c98San Mehattypedef unsigned short u16; 64ffd68729961f7383f2e35494a03ccdef20f86c98San Mehattypedef unsigned int u32; 65ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 66ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstruct dhcp_packet { 67ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat u8 op, htype, hlen, hops; 68ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat u32 xid; 69ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat u16 secs, flags; 70ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr ciaddr, yiaddr, siaddr, giaddr; 71ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128]; 72ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat u32 cookie; 73ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char options[308]; 74ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat}; 75ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 76ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct iovec iov; 77ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 78ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic int expand_buf(struct iovec *iov, size_t size) 79ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 80ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat void *new; 81ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 82ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (size <= iov->iov_len) 83ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 1; 84ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 85ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!(new = malloc(size))) 86ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 87ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat errno = ENOMEM; 88ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 0; 89ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 90ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 91ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (iov->iov_base) 92ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 93ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcpy(new, iov->iov_base, iov->iov_len); 94ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat free(iov->iov_base); 95ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 96ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 97ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iov->iov_base = new; 98ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iov->iov_len = size; 99ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 100ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 1; 101ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 102ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 103ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic ssize_t netlink_recv(int fd) 104ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 105ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct msghdr msg; 106ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ssize_t rc; 107ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 108ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_control = NULL; 109ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_controllen = 0; 110ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_name = NULL; 111ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_namelen = 0; 112ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_iov = &iov; 113ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_iovlen = 1; 114ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 115ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while (1) 116ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 117ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat msg.msg_flags = 0; 118ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while ((rc = recvmsg(fd, &msg, MSG_PEEK)) == -1 && errno == EINTR); 119ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 120ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* 2.2.x doesn't suport MSG_PEEK at all, returning EOPNOTSUPP, so we just grab a 121ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat big buffer and pray in that case. */ 122ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (rc == -1 && errno == EOPNOTSUPP) 123ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 124ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!expand_buf(&iov, 2000)) 125ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return -1; 126ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 127ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 128ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 129ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (rc == -1 || !(msg.msg_flags & MSG_TRUNC)) 130ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat break; 131ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 132ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (!expand_buf(&iov, iov.iov_len + 100)) 133ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return -1; 134ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 135ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 136ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* finally, read it for real */ 137ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while ((rc = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR); 138ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 139ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return rc; 140ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 141ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 142ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic int parse_hex(char *in, unsigned char *out, int maxlen, int *mac_type) 143ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 144ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int i = 0; 145ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat char *r; 146ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 147ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (mac_type) 148ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *mac_type = 0; 149ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 150ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while (maxlen == -1 || i < maxlen) 151ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 152ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (r = in; *r != 0 && *r != ':' && *r != '-'; r++); 153ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (*r == 0) 154ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat maxlen = i; 155ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 156ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (r != in ) 157ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 158ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (*r == '-' && i == 0 && mac_type) 159ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 160ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *r = 0; 161ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *mac_type = strtol(in, NULL, 16); 162ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat mac_type = NULL; 163ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 164ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 165ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 166ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *r = 0; 167ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat out[i] = strtol(in, NULL, 16); 168ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat i++; 169ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 170ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 171ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat in = r+1; 172ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 173ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return i; 174ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 175ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 176ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask) 177ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 178ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr); 179ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 180ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 181ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatstatic struct in_addr find_interface(struct in_addr client, int fd, int index) 182ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 183ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct sockaddr_nl addr; 184ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct nlmsghdr *h; 185ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat ssize_t len; 186ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 187ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct { 188ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct nlmsghdr nlh; 189ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct rtgenmsg g; 190ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } req; 191ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 192ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.nl_family = AF_NETLINK; 193ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.nl_pad = 0; 194ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.nl_groups = 0; 195ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.nl_pid = 0; /* address to kernel */ 196ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 197ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat req.nlh.nlmsg_len = sizeof(req); 198ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat req.nlh.nlmsg_type = RTM_GETADDR; 199ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK; 200ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat req.nlh.nlmsg_pid = 0; 201ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat req.nlh.nlmsg_seq = 1; 202ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat req.g.rtgen_family = AF_INET; 203ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 204ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (sendto(fd, (void *)&req, sizeof(req), 0, 205ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (struct sockaddr *)&addr, sizeof(addr)) == -1) 206ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 207ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat perror("sendto failed"); 208ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat exit(1); 209ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 210ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 211ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat while (1) 212ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 213ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if ((len = netlink_recv(fd)) == -1) 214ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 215ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat perror("netlink"); 216ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat exit(1); 217ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 218ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 219ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len)) 220ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (h->nlmsg_type == NLMSG_DONE) 221ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat exit(0); 222ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else if (h->nlmsg_type == RTM_NEWADDR) 223ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 224ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct ifaddrmsg *ifa = NLMSG_DATA(h); 225ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct rtattr *rta; 226ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)); 227ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 228ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (ifa->ifa_index == index && ifa->ifa_family == AF_INET) 229ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 230ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr netmask, addr; 231ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 232ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen)); 233ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr.s_addr = 0; 234ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 235ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat for (rta = IFA_RTA(ifa); RTA_OK(rta, len1); rta = RTA_NEXT(rta, len1)) 236ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (rta->rta_type == IFA_LOCAL) 237ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat addr = *((struct in_addr *)(rta+1)); 238ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 239ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (addr.s_addr && is_same_net(addr, client, netmask)) 240ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return addr; 241ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 242ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 243ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 244ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 245ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat exit(0); 246ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 247ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 248ffd68729961f7383f2e35494a03ccdef20f86c98San Mehatint main(int argc, char **argv) 249ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat{ 250ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct in_addr server, lease; 251ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int mac_type; 252ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct dhcp_packet packet; 253ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned char *p = packet.options; 254ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct sockaddr_in dest; 255ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct ifreq ifr; 256ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 257ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat int nl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 258ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat struct iovec iov; 259ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 260ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iov.iov_len = 200; 261ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat iov.iov_base = malloc(iov.iov_len); 262ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 263ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (argc < 4 || argc > 5) 264ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 265ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat fprintf(stderr, "usage: dhcp_release <interface> <addr> <mac> [<client_id>]\n"); 266ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat exit(1); 267ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 268ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 269ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (fd == -1 || nl == -1) 270ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 271ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat perror("cannot create socket"); 272ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat exit(1); 273ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 274ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 275ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat /* This voodoo fakes up a packet coming from the correct interface, which really matters for 276ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat a DHCP server */ 277ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat strcpy(ifr.ifr_name, argv[1]); 278ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1) 279ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 280ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat perror("cannot setup interface"); 281ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat exit(1); 282ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 283ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 284ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 285ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat lease.s_addr = inet_addr(argv[2]); 286ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat server = find_interface(lease, nl, if_nametoindex(argv[1])); 287ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 288ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memset(&packet, 0, sizeof(packet)); 289ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 290ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat packet.hlen = parse_hex(argv[3], packet.chaddr, DHCP_CHADDR_MAX, &mac_type); 291ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (mac_type == 0) 292ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat packet.htype = ARPHRD_ETHER; 293ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat else 294ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat packet.htype = mac_type; 295ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 296ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat packet.op = BOOTREQUEST; 297ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat packet.ciaddr = lease; 298ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat packet.cookie = htonl(DHCP_COOKIE); 299ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 300ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *(p++) = OPTION_MESSAGE_TYPE; 301ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *(p++) = 1; 302ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *(p++) = DHCPRELEASE; 303ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 304ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *(p++) = OPTION_SERVER_IDENTIFIER; 305ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *(p++) = sizeof(server); 306ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat memcpy(p, &server, sizeof(server)); 307ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += sizeof(server); 308ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 309ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (argc == 5 && strcmp(argv[4], "*") != 0) 310ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 311ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat unsigned int clid_len = parse_hex(argv[4], p+2, 255, NULL); 312ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *(p++) = OPTION_CLIENT_ID; 313ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *(p++) = clid_len; 314ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat p += clid_len; 315ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 316ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 317ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat *(p++) = OPTION_END; 318ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 319ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_family = AF_INET; 320ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_port = ntohs(DHCP_SERVER_PORT); 321ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat dest.sin_addr = server; 322ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 323ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat if (sendto(fd, &packet, sizeof(packet), 0, 324ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat (struct sockaddr *)&dest, sizeof(dest)) == -1) 325ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat { 326ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat perror("sendto failed"); 327ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat exit(1); 328ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat } 329ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat 330ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat return 0; 331ffd68729961f7383f2e35494a03ccdef20f86c98San Mehat} 332