blob: 5526b474c054c96aa34e9aa2b83cdf7f22182c2f [file] [log] [blame]
Simon Kelley0a852542005-03-23 20:28:59 +00001/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11*/
12
13/* Author's email: simon@thekelleys.org.uk */
14
15#include "dnsmasq.h"
16
17#ifdef HAVE_RTNETLINK
18
19#include <linux/netlink.h>
20#include <linux/rtnetlink.h>
21
22int netlink_init(void)
23{
24 struct sockaddr_nl addr;
25 int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
26
27 if (sock < 0)
28 return -1; /* no kernel support */
29
30 addr.nl_family = AF_NETLINK;
31 addr.nl_pad = 0;
32 addr.nl_pid = getpid();
33 addr.nl_groups = 0;
34
35 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
36 die("cannot bind netlink socket: %s", NULL);
37
38 return sock;
39}
40
41
42/* We borrow the DNS packet buffer here. (The DHCP one already has a packet in it)
43 Since it's used only within this routine, that's fine, just remember
44 that calling icmp_echo() will trash it */
45int netlink_process(struct daemon *daemon, int index, struct in_addr relay,
46 struct in_addr primary, struct dhcp_context **retp)
47{
48 struct sockaddr_nl addr;
49 struct nlmsghdr *h;
50 int len, found_primary = 0;
51 struct dhcp_context *ret = NULL;
52 static unsigned int seq = 0;
53
54 struct {
55 struct nlmsghdr nlh;
56 struct rtgenmsg g;
57 } req;
58
59 if (daemon->netlinkfd == -1)
60 return 0;
61
62 addr.nl_family = AF_NETLINK;
63 addr.nl_pad = 0;
64 addr.nl_groups = 0;
65 addr.nl_pid = 0; /* address to kernel */
66
67 req.nlh.nlmsg_len = sizeof(req);
68 req.nlh.nlmsg_type = RTM_GETADDR;
69 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
70 req.nlh.nlmsg_pid = 0;
71 req.nlh.nlmsg_seq = ++seq;
72 req.g.rtgen_family = AF_INET;
73
74 /* Don't block in recvfrom if send fails */
75 while((len = sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0,
76 (struct sockaddr *)&addr, sizeof(addr))) == -1 && retry_send());
77
78 if (len == -1)
79 {
80 /* if RTnetlink not configured in the kernel, don't keep trying. */
81 if (errno == ECONNREFUSED)
82 {
83 close(daemon->netlinkfd);
84 daemon->netlinkfd = -1;
85 }
86 return 0;
87 }
88
89 get_next:
90 while((len = recvfrom(daemon->netlinkfd, daemon->packet, daemon->packet_buff_sz,
91 MSG_WAITALL, NULL, 0)) == -1 && retry_send());
92
93 if (len == -1)
94 return 0;
95
96 h = (struct nlmsghdr *)daemon->packet;
97
98 while (NLMSG_OK(h, (unsigned int)len))
99 {
100
101 if (h->nlmsg_seq != seq)
102 goto get_next;
103
104 if (h->nlmsg_type == NLMSG_DONE)
105 break;
106
107 if (h->nlmsg_type == NLMSG_ERROR)
108 return 0;
109
110 if (h->nlmsg_type == RTM_NEWADDR)
111 {
112 struct ifaddrmsg *ifa = NLMSG_DATA(h);
113
114 if (ifa->ifa_index == index && ifa->ifa_family == AF_INET)
115 {
116 struct rtattr *rta = IFA_RTA(ifa);
117 unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
118 struct in_addr netmask, addr, broadcast;
119
120 netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
121 addr.s_addr = 0;
122 broadcast.s_addr = 0;
123
124 while (RTA_OK(rta, len1))
125 {
126 if (rta->rta_type == IFA_LOCAL)
127 addr = *((struct in_addr *)(rta+1));
128 else if (rta->rta_type == IFA_BROADCAST)
129 broadcast = *((struct in_addr *)(rta+1));
130
131 rta = RTA_NEXT(rta, len1);
132 }
133
134 if (addr.s_addr && broadcast.s_addr)
135 {
136 ret = complete_context(daemon, addr, ret, netmask, broadcast, relay, primary);
137 if (addr.s_addr == primary.s_addr)
138 found_primary = 1;
139 }
140 }
141 }
142
143 h = NLMSG_NEXT(h, len);
144 }
145
146 *retp = ret;
147
148 return found_primary;
149}
150
151#endif
152
153