Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/networking/udhcp/dhcprelay.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 816 - (hide annotations) (download)
Fri Apr 24 18:33:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 7631 byte(s)
-updated to busybox-1.13.4
1 niro 532 /* vi: set sw=4 ts=4: */
2     /* Port to Busybox Copyright (C) 2006 Jesse Dutton <jessedutton@gmail.com>
3     *
4     * Licensed under GPL v2, see file LICENSE in this tarball for details.
5     *
6     * DHCP Relay for 'DHCPv4 Configuration of IPSec Tunnel Mode' support
7     * Copyright (C) 2002 Mario Strasser <mast@gmx.net>,
8     * Zuercher Hochschule Winterthur,
9     * Netbeat AG
10     * Upstream has GPL v2 or later
11     */
12    
13     #include "common.h"
14     #include "options.h"
15    
16     /* constants */
17 niro 816 #define SERVER_PORT 67
18     #define SELECT_TIMEOUT 5 /* select timeout in sec. */
19     #define MAX_LIFETIME 2*60 /* lifetime of an xid entry in sec. */
20 niro 532
21     /* This list holds information about clients. The xid_* functions manipulate this list. */
22 niro 816 struct xid_item {
23     unsigned timestamp;
24     int client;
25     uint32_t xid;
26 niro 532 struct sockaddr_in ip;
27     struct xid_item *next;
28 niro 816 };
29 niro 532
30 niro 816 #define dhcprelay_xid_list (*(struct xid_item*)&bb_common_bufsiz1)
31 niro 532
32 niro 816 static struct xid_item *xid_add(uint32_t xid, struct sockaddr_in *ip, int client)
33 niro 532 {
34     struct xid_item *item;
35    
36     /* create new xid entry */
37     item = xmalloc(sizeof(struct xid_item));
38    
39     /* add xid entry */
40     item->ip = *ip;
41     item->xid = xid;
42     item->client = client;
43 niro 816 item->timestamp = monotonic_sec();
44 niro 532 item->next = dhcprelay_xid_list.next;
45     dhcprelay_xid_list.next = item;
46    
47     return item;
48     }
49    
50     static void xid_expire(void)
51     {
52     struct xid_item *item = dhcprelay_xid_list.next;
53     struct xid_item *last = &dhcprelay_xid_list;
54 niro 816 unsigned current_time = monotonic_sec();
55 niro 532
56     while (item != NULL) {
57 niro 816 if ((current_time - item->timestamp) > MAX_LIFETIME) {
58 niro 532 last->next = item->next;
59     free(item);
60     item = last->next;
61     } else {
62     last = item;
63     item = item->next;
64     }
65     }
66     }
67    
68 niro 816 static struct xid_item *xid_find(uint32_t xid)
69 niro 532 {
70     struct xid_item *item = dhcprelay_xid_list.next;
71     while (item != NULL) {
72     if (item->xid == xid) {
73     return item;
74     }
75     item = item->next;
76     }
77     return NULL;
78     }
79    
80 niro 816 static void xid_del(uint32_t xid)
81 niro 532 {
82     struct xid_item *item = dhcprelay_xid_list.next;
83     struct xid_item *last = &dhcprelay_xid_list;
84     while (item != NULL) {
85     if (item->xid == xid) {
86     last->next = item->next;
87     free(item);
88     item = last->next;
89     } else {
90     last = item;
91     item = item->next;
92     }
93     }
94     }
95    
96     /**
97     * get_dhcp_packet_type - gets the message type of a dhcp packet
98     * p - pointer to the dhcp packet
99     * returns the message type on success, -1 otherwise
100     */
101     static int get_dhcp_packet_type(struct dhcpMessage *p)
102     {
103     uint8_t *op;
104    
105     /* it must be either a BOOTREQUEST or a BOOTREPLY */
106     if (p->op != BOOTREQUEST && p->op != BOOTREPLY)
107     return -1;
108     /* get message type option */
109     op = get_option(p, DHCP_MESSAGE_TYPE);
110     if (op != NULL)
111     return op[0];
112     return -1;
113     }
114    
115     /**
116     * get_client_devices - parses the devices list
117     * dev_list - comma separated list of devices
118     * returns array
119     */
120 niro 816 static char **get_client_devices(char *dev_list, int *client_number)
121 niro 532 {
122 niro 816 char *s, **client_dev;
123 niro 532 int i, cn;
124    
125     /* copy list */
126 niro 816 dev_list = xstrdup(dev_list);
127 niro 532
128 niro 816 /* get number of items, replace ',' with NULs */
129     s = dev_list;
130     cn = 1;
131     while (*s) {
132     if (*s == ',') {
133     *s = '\0';
134 niro 532 cn++;
135 niro 816 }
136     s++;
137     }
138     *client_number = cn;
139 niro 532
140 niro 816 /* create vector of pointers */
141 niro 532 client_dev = xzalloc(cn * sizeof(*client_dev));
142 niro 816 client_dev[0] = dev_list;
143     i = 1;
144     while (i != cn) {
145     client_dev[i] = client_dev[i - 1] + strlen(client_dev[i - 1]) + 1;
146     i++;
147 niro 532 }
148     return client_dev;
149     }
150    
151    
152 niro 816 /* Creates listen sockets (in fds) and returns numerically max fd. */
153 niro 532 static int init_sockets(char **client, int num_clients,
154 niro 816 char *server, int *fds)
155 niro 532 {
156 niro 816 int i, n;
157 niro 532
158     /* talk to real server on bootps */
159 niro 816 fds[0] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, server);
160     n = fds[0];
161 niro 532
162 niro 816 for (i = 1; i < num_clients; i++) {
163 niro 532 /* listen for clients on bootps */
164 niro 816 fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, client[i-1]);
165     if (fds[i] > n)
166     n = fds[i];
167 niro 532 }
168 niro 816 return n;
169 niro 532 }
170    
171    
172     /**
173     * pass_on() - forwards dhcp packets from client to server
174     * p - packet to send
175     * client - number of the client
176     */
177     static void pass_on(struct dhcpMessage *p, int packet_len, int client, int *fds,
178     struct sockaddr_in *client_addr, struct sockaddr_in *server_addr)
179     {
180     int res, type;
181     struct xid_item *item;
182    
183     /* check packet_type */
184     type = get_dhcp_packet_type(p);
185     if (type != DHCPDISCOVER && type != DHCPREQUEST
186     && type != DHCPDECLINE && type != DHCPRELEASE
187     && type != DHCPINFORM
188     ) {
189     return;
190     }
191    
192     /* create new xid entry */
193     item = xid_add(p->xid, client_addr, client);
194    
195     /* forward request to LAN (server) */
196     res = sendto(fds[0], p, packet_len, 0, (struct sockaddr*)server_addr,
197     sizeof(struct sockaddr_in));
198     if (res != packet_len) {
199     bb_perror_msg("pass_on");
200     return;
201     }
202     }
203    
204     /**
205     * pass_back() - forwards dhcp packets from server to client
206     * p - packet to send
207     */
208     static void pass_back(struct dhcpMessage *p, int packet_len, int *fds)
209     {
210     int res, type;
211     struct xid_item *item;
212    
213     /* check xid */
214     item = xid_find(p->xid);
215     if (!item) {
216     return;
217     }
218    
219     /* check packet type */
220     type = get_dhcp_packet_type(p);
221     if (type != DHCPOFFER && type != DHCPACK && type != DHCPNAK) {
222     return;
223     }
224    
225     if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY))
226     item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST);
227     res = sendto(fds[item->client], p, packet_len, 0, (struct sockaddr*)(&item->ip),
228     sizeof(item->ip));
229     if (res != packet_len) {
230     bb_perror_msg("pass_back");
231     return;
232     }
233    
234     /* remove xid entry */
235     xid_del(p->xid);
236     }
237    
238     static void dhcprelay_loop(int *fds, int num_sockets, int max_socket, char **clients,
239 niro 816 struct sockaddr_in *server_addr, uint32_t gw_ip) NORETURN;
240     static void dhcprelay_loop(int *fds, int num_sockets, int max_socket, char **clients,
241 niro 532 struct sockaddr_in *server_addr, uint32_t gw_ip)
242     {
243     struct dhcpMessage dhcp_msg;
244     fd_set rfds;
245     size_t packlen;
246     socklen_t addr_size;
247     struct sockaddr_in client_addr;
248     struct timeval tv;
249     int i;
250    
251 niro 816 while (1) {
252 niro 532 FD_ZERO(&rfds);
253     for (i = 0; i < num_sockets; i++)
254     FD_SET(fds[i], &rfds);
255     tv.tv_sec = SELECT_TIMEOUT;
256     tv.tv_usec = 0;
257     if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) {
258     /* server */
259     if (FD_ISSET(fds[0], &rfds)) {
260 niro 816 packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]);
261 niro 532 if (packlen > 0) {
262     pass_back(&dhcp_msg, packlen, fds);
263     }
264     }
265     for (i = 1; i < num_sockets; i++) {
266     /* clients */
267     if (!FD_ISSET(fds[i], &rfds))
268     continue;
269     addr_size = sizeof(struct sockaddr_in);
270     packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0,
271     (struct sockaddr *)(&client_addr), &addr_size);
272     if (packlen <= 0)
273     continue;
274 niro 816 if (udhcp_read_interface(clients[i-1], NULL, &dhcp_msg.giaddr, NULL))
275 niro 532 dhcp_msg.giaddr = gw_ip;
276     pass_on(&dhcp_msg, packlen, i, fds, &client_addr, server_addr);
277     }
278     }
279     xid_expire();
280     }
281     }
282    
283 niro 816 int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
284 niro 532 int dhcprelay_main(int argc, char **argv)
285     {
286 niro 816 int num_sockets, max_socket;
287     int *fds;
288 niro 532 uint32_t gw_ip;
289     char **clients;
290     struct sockaddr_in server_addr;
291    
292     server_addr.sin_family = AF_INET;
293 niro 816 server_addr.sin_port = htons(SERVER_PORT);
294 niro 532 if (argc == 4) {
295     if (!inet_aton(argv[3], &server_addr.sin_addr))
296     bb_perror_msg_and_die("didn't grok server");
297     } else if (argc == 3) {
298     server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
299     } else {
300     bb_show_usage();
301     }
302 niro 816
303 niro 532 clients = get_client_devices(argv[1], &num_sockets);
304 niro 816 num_sockets++; /* for server socket at fds[0] */
305     fds = xmalloc(num_sockets * sizeof(fds[0]));
306     max_socket = init_sockets(clients, num_sockets, argv[2], fds);
307 niro 532
308 niro 816 if (udhcp_read_interface(argv[2], NULL, &gw_ip, NULL))
309 niro 532 return 1;
310    
311 niro 816 /* doesn't return */
312 niro 532 dhcprelay_loop(fds, num_sockets, max_socket, clients, &server_addr, gw_ip);
313 niro 816 /* return 0; - not reached */
314 niro 532 }