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