import of dnsmasq-2.34.tar.gz

This commit is contained in:
Simon Kelley
2006-10-16 20:04:18 +01:00
parent 208b65c5cf
commit 1697269ce7
33 changed files with 3660 additions and 2711 deletions

View File

@@ -44,6 +44,10 @@
#include <stdlib.h>
#include <net/if_arp.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <errno.h>
#define DHCP_CHADDR_MAX 16
#define BOOTREQUEST 1
@@ -69,6 +73,72 @@ struct dhcp_packet {
unsigned char options[308];
};
static struct iovec iov;
static int expand_buf(struct iovec *iov, size_t size)
{
void *new;
if (size <= iov->iov_len)
return 1;
if (!(new = malloc(size)))
{
errno = ENOMEM;
return 0;
}
if (iov->iov_base)
{
memcpy(new, iov->iov_base, iov->iov_len);
free(iov->iov_base);
}
iov->iov_base = new;
iov->iov_len = size;
return 1;
}
static ssize_t netlink_recv(int fd)
{
struct msghdr msg;
ssize_t rc;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
while (1)
{
msg.msg_flags = 0;
while ((rc = recvmsg(fd, &msg, MSG_PEEK)) == -1 && errno == EINTR);
/* 2.2.x doesn't suport MSG_PEEK at all, returning EOPNOTSUPP, so we just grab a
big buffer and pray in that case. */
if (rc == -1 && errno == EOPNOTSUPP)
{
if (!expand_buf(&iov, 2000))
return -1;
break;
}
if (rc == -1 || !(msg.msg_flags & MSG_TRUNC))
break;
if (!expand_buf(&iov, iov.iov_len + 100))
return -1;
}
/* finally, read it for real */
while ((rc = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR);
return rc;
}
static int parse_hex(char *in, unsigned char *out, int maxlen, int *mac_type)
{
int i = 0;
@@ -103,6 +173,78 @@ static int parse_hex(char *in, unsigned char *out, int maxlen, int *mac_type)
return i;
}
static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
{
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
}
static struct in_addr find_interface(struct in_addr client, int fd, int index)
{
struct sockaddr_nl addr;
struct nlmsghdr *h;
ssize_t len;
struct {
struct nlmsghdr nlh;
struct rtgenmsg g;
} req;
addr.nl_family = AF_NETLINK;
addr.nl_pad = 0;
addr.nl_groups = 0;
addr.nl_pid = 0; /* address to kernel */
req.nlh.nlmsg_len = sizeof(req);
req.nlh.nlmsg_type = RTM_GETADDR;
req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK;
req.nlh.nlmsg_pid = 0;
req.nlh.nlmsg_seq = 1;
req.g.rtgen_family = AF_INET;
if (sendto(fd, (void *)&req, sizeof(req), 0,
(struct sockaddr *)&addr, sizeof(addr)) == -1)
{
perror("sendto failed");
exit(1);
}
while (1)
{
if ((len = netlink_recv(fd)) == -1)
{
perror("netlink");
exit(1);
}
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
if (h->nlmsg_type == NLMSG_DONE)
exit(0);
else if (h->nlmsg_type == RTM_NEWADDR)
{
struct ifaddrmsg *ifa = NLMSG_DATA(h);
struct rtattr *rta;
unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
if (ifa->ifa_index == index && ifa->ifa_family == AF_INET)
{
struct in_addr netmask, addr;
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
addr.s_addr = 0;
for (rta = IFA_RTA(ifa); RTA_OK(rta, len1); rta = RTA_NEXT(rta, len1))
if (rta->rta_type == IFA_LOCAL)
addr = *((struct in_addr *)(rta+1));
if (addr.s_addr && is_same_net(addr, client, netmask))
return addr;
}
}
}
exit(0);
}
int main(int argc, char **argv)
{
struct in_addr server, lease;
@@ -112,6 +254,11 @@ int main(int argc, char **argv)
struct sockaddr_in dest;
struct ifreq ifr;
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
int nl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
struct iovec iov;
iov.iov_len = 200;
iov.iov_base = malloc(iov.iov_len);
if (argc < 4 || argc > 5)
{
@@ -119,7 +266,7 @@ int main(int argc, char **argv)
exit(1);
}
if (fd == -1)
if (fd == -1 || nl == -1)
{
perror("cannot create socket");
exit(1);
@@ -128,15 +275,15 @@ int main(int argc, char **argv)
/* This voodoo fakes up a packet coming from the correct interface, which really matters for
a DHCP server */
strcpy(ifr.ifr_name, argv[1]);
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(fd, SIOCGIFADDR, &ifr) == -1 || setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
{
perror("cannot setup interface");
exit(1);
}
server = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
lease.s_addr = inet_addr(argv[2]);
server = find_interface(lease, nl, if_nametoindex(argv[1]));
memset(&packet, 0, sizeof(packet));
@@ -174,7 +321,7 @@ int main(int argc, char **argv)
dest.sin_addr = server;
if (sendto(fd, &packet, sizeof(packet), 0,
(struct sockaddr *)&dest, sizeof(dest)) == 1)
(struct sockaddr *)&dest, sizeof(dest)) == -1)
{
perror("sendto failed");
exit(1);