• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/relayd/main.c

  1 /*
  2  *   Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
  3  *
  4  *   This program is free software; you can redistribute it and/or modify
  5  *   it under the terms of the GNU General Public License v2 as published by
  6  *   the Free Software Foundation.
  7  *
  8  *   This program is distributed in the hope that it will be useful,
  9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11  *   GNU General Public License for more details.
 12  *
 13  *   You should have received a copy of the GNU General Public License
 14  *   along with this program; if not, write to the Free Software
 15  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 16  *
 17  */
 18 #include <sys/ioctl.h>
 19 #include <sys/socket.h>
 20 
 21 #include <stdio.h>
 22 #include <unistd.h>
 23 #include <fcntl.h>
 24 #include <stddef.h>
 25 #include <stdlib.h>
 26 #include <stdint.h>
 27 #include <stdbool.h>
 28 #include <errno.h>
 29 #include <signal.h>
 30 #include <string.h>
 31 
 32 #include "relayd.h"
 33 
 34 static LIST_HEAD(pending_routes);
 35 LIST_HEAD(interfaces);
 36 int debug;
 37 
 38 static int host_timeout;
 39 static int host_ping_tries;
 40 static int inet_sock;
 41 static int forward_bcast;
 42 static int forward_dhcp;
 43 static int parse_dhcp;
 44 
 45 uint8_t local_addr[4];
 46 int local_route_table;
 47 
 48 struct relayd_pending_route {
 49         struct relayd_route rt;
 50         struct uloop_timeout timeout;
 51         uint8_t gateway[4];
 52 };
 53 
 54 static struct relayd_host *find_host_by_ipaddr(struct relayd_interface *rif, const uint8_t *ipaddr)
 55 {
 56         struct relayd_host *host;
 57 
 58         if (!rif) {
 59                 list_for_each_entry(rif, &interfaces, list) {
 60                         host = find_host_by_ipaddr(rif, ipaddr);
 61                         if (!host)
 62                                 continue;
 63 
 64                         return host;
 65                 }
 66                 return NULL;
 67         }
 68 
 69         list_for_each_entry(host, &rif->hosts, list) {
 70                 if (memcmp(ipaddr, host->ipaddr, sizeof(host->ipaddr)) != 0)
 71                         continue;
 72 
 73                 return host;
 74         }
 75         return NULL;
 76 }
 77 
 78 static void add_arp(struct relayd_host *host)
 79 {
 80         struct sockaddr_in *sin;
 81         struct arpreq arp;
 82 
 83         strncpy(arp.arp_dev, host->rif->ifname, sizeof(arp.arp_dev));
 84         arp.arp_flags = ATF_COM;
 85 
 86         arp.arp_ha.sa_family = ARPHRD_ETHER;
 87         memcpy(arp.arp_ha.sa_data, host->lladdr, ETH_ALEN);
 88 
 89         sin = (struct sockaddr_in *) &arp.arp_pa;
 90         sin->sin_family = AF_INET;
 91         memcpy(&sin->sin_addr, host->ipaddr, sizeof(host->ipaddr));
 92 
 93         ioctl(inet_sock, SIOCSARP, &arp);
 94 }
 95 
 96 static void timeout_host_route(struct uloop_timeout *timeout)
 97 {
 98         struct relayd_pending_route *rt;
 99 
100         rt = container_of(timeout, struct relayd_pending_route, timeout);
101         list_del(&rt->rt.list);
102         free(rt);
103 }
104 
105 void relayd_add_host_route(struct relayd_host *host, const uint8_t *dest, uint8_t mask)
106 {
107         struct relayd_route *rt;
108 
109         list_for_each_entry(rt, &host->routes, list) {
110                 if (!memcmp(rt->dest, dest, sizeof(rt->dest)) && rt->mask == mask)
111                         return;
112         }
113 
114         rt = calloc(1, sizeof(*rt));
115         if (!rt)
116                 return;
117 
118         list_add(&rt->list, &host->routes);
119         memcpy(rt->dest, dest, sizeof(rt->dest));
120         rt->mask = mask;
121         relayd_add_route(host, rt);
122 }
123 
124 static void del_host(struct relayd_host *host)
125 {
126         struct relayd_route *route, *tmp;
127 
128         DPRINTF(1, "%s: deleting host "IP_FMT" ("MAC_FMT")\n", host->rif->ifname,
129                 IP_BUF(host->ipaddr), MAC_BUF(host->lladdr));
130 
131         list_for_each_entry_safe(route, tmp, &host->routes, list) {
132                 relayd_del_route(host, route);
133                 list_del(&route->list);
134                 free(route);
135         }
136         if (host->rif->managed)
137                 relayd_del_route(host, NULL);
138         uloop_timeout_cancel(&host->timeout);
139         list_del(&host->list);
140         free(host);
141 }
142 
143 static void fill_arp_packet(struct arp_packet *pkt, struct relayd_interface *rif,
144                              const uint8_t spa[4], const uint8_t tpa[4])
145 {
146         memset(pkt, 0, sizeof(*pkt));
147 
148         pkt->eth.ether_type = htons(ETHERTYPE_ARP);
149         memcpy(pkt->eth.ether_shost, rif->sll.sll_addr, ETH_ALEN);
150 
151         memcpy(pkt->arp.arp_sha, rif->sll.sll_addr, ETH_ALEN);
152         memcpy(pkt->arp.arp_spa, spa, 4);
153         memcpy(pkt->arp.arp_tpa, tpa, 4);
154 
155         pkt->arp.arp_hrd = htons(ARPHRD_ETHER);
156         pkt->arp.arp_pro = htons(ETH_P_IP);
157         pkt->arp.arp_hln = ETH_ALEN;
158         pkt->arp.arp_pln = 4;
159 }
160 
161 static void send_arp_request(struct relayd_interface *rif, const uint8_t *ipaddr)
162 {
163         struct arp_packet pkt;
164 
165         fill_arp_packet(&pkt, rif, rif->src_ip, ipaddr);
166 
167         pkt.arp.arp_op = htons(ARPOP_REQUEST);
168         memcpy(pkt.arp.arp_spa, rif->src_ip, sizeof(pkt.arp.arp_spa));
169         memset(pkt.arp.arp_tha, 0, ETH_ALEN);
170         memset(pkt.eth.ether_dhost, 0xff, ETH_ALEN);
171 
172         DPRINTF(2, "%s: sending ARP who-has "IP_FMT", tell "IP_FMT" ("MAC_FMT")\n",
173                 rif->ifname, IP_BUF(pkt.arp.arp_tpa),
174                 IP_BUF(pkt.arp.arp_spa), MAC_BUF(pkt.eth.ether_shost));
175 
176         sendto(rif->fd.fd, &pkt, sizeof(pkt), 0,
177                 (struct sockaddr *) &rif->sll, sizeof(rif->sll));
178 }
179 
180 void relayd_add_pending_route(const uint8_t *gateway, const uint8_t *dest, uint8_t mask, int timeout)
181 {
182         struct relayd_pending_route *rt;
183         struct relayd_interface *rif;
184         struct relayd_host *host;
185 
186         host = find_host_by_ipaddr(NULL, gateway);
187         if (host) {
188                 relayd_add_host_route(host, dest, mask);
189                 return;
190         }
191 
192         rt = calloc(1, sizeof(*rt));
193         if (!rt)
194                 return;
195 
196         memcpy(rt->gateway, gateway, sizeof(rt->gateway));
197         memcpy(rt->rt.dest, dest, sizeof(rt->rt.dest));
198         rt->rt.mask = mask;
199         list_add(&rt->rt.list, &pending_routes);
200         if (timeout <= 0)
201                 return;
202 
203         rt->timeout.cb = timeout_host_route;
204         uloop_timeout_set(&rt->timeout, 10000);
205         list_for_each_entry(rif, &interfaces, list) {
206                 send_arp_request(rif, gateway);
207         }
208 }
209 
210 static void send_arp_reply(struct relayd_interface *rif, const uint8_t spa[4],
211                            const uint8_t tha[ETH_ALEN], const uint8_t tpa[4])
212 {
213         struct arp_packet pkt;
214 
215         fill_arp_packet(&pkt, rif, spa, tpa);
216 
217         if (tha) {
218                 pkt.arp.arp_op = htons(ARPOP_REPLY);
219                 memcpy(pkt.eth.ether_dhost, tha, ETH_ALEN);
220                 memcpy(pkt.arp.arp_tha, tha, ETH_ALEN);
221 
222                 DPRINTF(2, "%s: sending ARP reply to "IP_FMT", "IP_FMT" is at ("MAC_FMT")\n",
223                         rif->ifname, IP_BUF(pkt.arp.arp_tpa),
224                         IP_BUF(pkt.arp.arp_spa), MAC_BUF(pkt.eth.ether_shost));
225         } else {
226                 pkt.arp.arp_op = htons(ARPOP_REQUEST);
227                 memset(pkt.eth.ether_dhost, 0xff, ETH_ALEN);
228                 memset(pkt.arp.arp_tha, 0xff, ETH_ALEN);
229 
230                 DPRINTF(2, "%s: sending gratuitous ARP: "IP_FMT" is at ("MAC_FMT")\n",
231                         rif->ifname, IP_BUF(pkt.arp.arp_tpa),
232                         MAC_BUF(pkt.eth.ether_shost));
233         }
234 
235         sendto(rif->fd.fd, &pkt, sizeof(pkt), 0,
236                 (struct sockaddr *) &rif->sll, sizeof(rif->sll));
237 
238         if (tha)
239                 return;
240 
241         /*
242          * Gratuitous ARP comes in two flavours, request and reply.
243          * Some operating systems only accept request, some only reply.
244          * Let's just send both...
245          */
246         pkt.arp.arp_op = htons(ARPOP_REPLY);
247 
248         sendto(rif->fd.fd, &pkt, sizeof(pkt), 0,
249                 (struct sockaddr *) &rif->sll, sizeof(rif->sll));
250 
251 }
252 
253 static void host_entry_timeout(struct uloop_timeout *timeout)
254 {
255         struct relayd_host *host = container_of(timeout, struct relayd_host, timeout);
256         struct relayd_interface *rif;
257 
258         /*
259          * When a host is behind a managed interface, we must not expire its host
260          * entry prematurely, as this will cause routes to the node to expire,
261          * leading to loss of connectivity from the other side.
262          * When the timeout is reached, try pinging the host a few times before
263          * giving up on it.
264          */
265         if (host->rif->managed && host->cleanup_pending < host_ping_tries) {
266                 list_for_each_entry(rif, &interfaces, list) {
267                         send_arp_request(rif, host->ipaddr);
268                 }
269                 host->cleanup_pending++;
270                 uloop_timeout_set(&host->timeout, 1000);
271                 return;
272         }
273         del_host(host);
274 }
275 
276 static struct relayd_host *add_host(struct relayd_interface *rif, const uint8_t *lladdr, const uint8_t *ipaddr)
277 {
278         struct relayd_host *host;
279         struct relayd_pending_route *route, *rtmp;
280 
281         DPRINTF(1, "%s: adding host "IP_FMT" ("MAC_FMT")\n", rif->ifname,
282                         IP_BUF(ipaddr), MAC_BUF(lladdr));
283 
284         host = calloc(1, sizeof(*host));
285         INIT_LIST_HEAD(&host->routes);
286         host->rif = rif;
287         memcpy(host->ipaddr, ipaddr, sizeof(host->ipaddr));
288         memcpy(host->lladdr, lladdr, sizeof(host->lladdr));
289         list_add(&host->list, &rif->hosts);
290         host->timeout.cb = host_entry_timeout;
291         uloop_timeout_set(&host->timeout, host_timeout * 1000);
292 
293         add_arp(host);
294         if (rif->managed)
295                 relayd_add_route(host, NULL);
296 
297         list_for_each_entry_safe(route, rtmp, &pending_routes, rt.list) {
298                 if (memcmp(route->gateway, ipaddr, 4) != 0)
299                         continue;
300 
301                 relayd_add_host_route(host, route->rt.dest, route->rt.mask);
302                 if (!route->timeout.pending)
303                         continue;
304 
305                 uloop_timeout_cancel(&route->timeout);
306                 list_del(&route->rt.list);
307                 free(route);
308         }
309 
310         return host;
311 }
312 
313 static void send_gratuitous_arp(struct relayd_interface *rif, const uint8_t *spa)
314 {
315         struct relayd_interface *to_rif;
316 
317         list_for_each_entry(to_rif, &interfaces, list) {
318                 if (rif == to_rif)
319                         continue;
320 
321                 send_arp_reply(to_rif, spa, NULL, spa);
322         }
323 }
324 
325 
326 struct relayd_host *relayd_refresh_host(struct relayd_interface *rif, const uint8_t *lladdr, const uint8_t *ipaddr)
327 {
328         struct relayd_host *host;
329 
330         host = find_host_by_ipaddr(rif, ipaddr);
331         if (!host) {
332                 host = find_host_by_ipaddr(NULL, ipaddr);
333 
334                 /* 
335                  * When we suddenly see the host appearing on a different interface,
336                  * reduce the timeout to make the old entry expire faster, in case the
337                  * host has moved.
338                  * If the old entry is behind a managed interface, it will be pinged
339                  * before we expire it
340                  */
341                 if (host && !host->cleanup_pending) {
342                         uloop_timeout_set(&host->timeout, 1);
343                         return NULL;
344                 }
345 
346                 host = add_host(rif, lladdr, ipaddr);
347         } else {
348                 host->cleanup_pending = false;
349                 uloop_timeout_set(&host->timeout, host_timeout * 1000);
350                 send_gratuitous_arp(rif, ipaddr);
351         }
352 
353         return host;
354 }
355 
356 static void relay_arp_request(struct relayd_interface *from_rif, struct arp_packet *pkt)
357 {
358         struct relayd_interface *rif;
359         struct arp_packet reqpkt;
360 
361         memcpy(&reqpkt, pkt, sizeof(reqpkt));
362         list_for_each_entry(rif, &interfaces, list) {
363                 if (rif == from_rif)
364                         continue;
365 
366                 memcpy(reqpkt.eth.ether_shost, rif->sll.sll_addr, ETH_ALEN);
367                 memset(reqpkt.eth.ether_dhost, 0xff, ETH_ALEN);
368                 memcpy(reqpkt.arp.arp_sha, rif->sll.sll_addr, ETH_ALEN);
369                 memset(reqpkt.arp.arp_tha, 0, ETH_ALEN);
370 
371                 DPRINTF(2, "%s: sending ARP who-has "IP_FMT", tell "IP_FMT" ("MAC_FMT")\n",
372                         rif->ifname, IP_BUF(reqpkt.arp.arp_tpa),
373                         IP_BUF(reqpkt.arp.arp_spa), MAC_BUF(reqpkt.eth.ether_shost));
374 
375                 sendto(rif->fd.fd, &reqpkt, sizeof(reqpkt), 0,
376                         (struct sockaddr *) &rif->sll, sizeof(rif->sll));
377         }
378 }
379 
380 static void recv_arp_request(struct relayd_interface *rif, struct arp_packet *pkt)
381 {
382         struct relayd_host *host;
383 
384         DPRINTF(2, "%s: ARP who-has "IP_FMT", tell "IP_FMT" ("MAC_FMT")\n",
385                 rif->ifname,
386                 IP_BUF(pkt->arp.arp_tpa),
387                 IP_BUF(pkt->arp.arp_spa),
388                 MAC_BUF(pkt->eth.ether_shost));
389 
390         if (!memcmp(pkt->arp.arp_spa, "\x00\x00\x00\x00", 4))
391                 return;
392 
393         host = find_host_by_ipaddr(NULL, pkt->arp.arp_spa);
394         if (!host || host->rif != rif)
395                 relayd_refresh_host(rif, pkt->eth.ether_shost, pkt->arp.arp_spa);
396 
397         if (local_route_table && !memcmp(pkt->arp.arp_tpa, local_addr, sizeof(local_addr))) {
398                 send_arp_reply(rif, local_addr, pkt->arp.arp_sha, pkt->arp.arp_spa);
399                 return;
400         }
401 
402         host = find_host_by_ipaddr(NULL, pkt->arp.arp_tpa);
403 
404         /*
405          * If a host is being pinged because of a timeout, do not use the cached
406          * entry here. That way we can avoid giving out stale data in case the node
407          * has moved. We shouldn't relay requests here either, as we might miss our
408          * chance to create a host route.
409          */
410         if (host && host->cleanup_pending)
411                 return;
412 
413         relay_arp_request(rif, pkt);
414 }
415 
416 static void recv_arp_reply(struct relayd_interface *rif, struct arp_packet *pkt)
417 {
418         struct relayd_host *host;
419 
420         DPRINTF(2, "%s: received ARP reply for "IP_FMT" from "MAC_FMT", deliver to "IP_FMT"\n",
421                 rif->ifname,
422                 IP_BUF(pkt->arp.arp_spa),
423                 MAC_BUF(pkt->eth.ether_shost),
424                 IP_BUF(pkt->arp.arp_tpa));
425 
426         if (memcmp(pkt->arp.arp_sha, rif->sll.sll_addr, ETH_ALEN) != 0)
427                 relayd_refresh_host(rif, pkt->arp.arp_sha, pkt->arp.arp_spa);
428 
429         host = find_host_by_ipaddr(NULL, pkt->arp.arp_tpa);
430         if (!host)
431                 return;
432 
433         if (host->rif == rif)
434                 return;
435 
436         send_arp_reply(host->rif, pkt->arp.arp_spa, host->lladdr, host->ipaddr);
437 }
438 
439 static void recv_packet(struct uloop_fd *fd, unsigned int events)
440 {
441         struct relayd_interface *rif = container_of(fd, struct relayd_interface, fd);
442         struct arp_packet *pkt;
443         static char pktbuf[4096];
444         int pktlen;
445 
446         do {
447                 if (rif->fd.error)
448                         uloop_end();
449 
450                 pktlen = recv(rif->fd.fd, pktbuf, sizeof(pktbuf), 0);
451                 if (pktlen < 0) {
452                         if (errno == EINTR)
453                                 continue;
454 
455                         break;
456                 }
457 
458                 if (!pktlen)
459                         break;
460 
461                 pkt = (void *)pktbuf;
462                 if (pkt->arp.arp_op == htons(ARPOP_REPLY))
463                         recv_arp_reply(rif, pkt);
464                 else if (pkt->arp.arp_op == htons(ARPOP_REQUEST))
465                         recv_arp_request(rif, pkt);
466                 else
467                         DPRINTF(1, "received unknown packet type: %04x\n", ntohs(pkt->arp.arp_op));
468 
469         } while (1);
470 }
471 
472 void relayd_forward_bcast_packet(struct relayd_interface *from_rif, void *packet, int len)
473 {
474         struct relayd_interface *rif;
475         struct ether_header *eth = packet;
476 
477         list_for_each_entry(rif, &interfaces, list) {
478                 if (rif == from_rif)
479                         continue;
480 
481                 DPRINTF(3, "%s: forwarding broadcast packet to %s\n", from_rif->ifname, rif->ifname);
482                 memcpy(eth->ether_shost, rif->sll.sll_addr, ETH_ALEN);
483                 send(rif->bcast_fd.fd, packet, len, 0);
484         }
485 }
486 
487 static void recv_bcast_packet(struct uloop_fd *fd, unsigned int events)
488 {
489         struct relayd_interface *rif = container_of(fd, struct relayd_interface, bcast_fd);
490         static char pktbuf[4096];
491         int pktlen;
492 
493         do {
494                 if (rif->fd.error)
495                         uloop_end();
496 
497                 pktlen = recv(rif->bcast_fd.fd, pktbuf, sizeof(pktbuf), 0);
498                 if (pktlen < 0) {
499                         if (errno == EINTR)
500                                 continue;
501 
502                         break;
503                 }
504 
505                 if (!pktlen)
506                         break;
507 
508                 if (!forward_bcast && !forward_dhcp)
509                         continue;
510 
511                 if (relayd_handle_dhcp_packet(rif, pktbuf, pktlen, forward_dhcp, parse_dhcp))
512                         continue;
513 
514                 if (forward_bcast)
515                         relayd_forward_bcast_packet(rif, pktbuf, pktlen);
516         } while (1);
517 }
518 
519 
520 static int init_interface(struct relayd_interface *rif)
521 {
522         struct sockaddr_ll *sll = &rif->sll;
523         struct sockaddr_in *sin;
524         struct ifreq ifr;
525         int fd = rif->fd.fd;
526 #ifdef PACKET_RECV_TYPE
527         unsigned int pkt_type;
528 #endif
529 
530         fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
531         if (fd < 0)
532                 return -1;
533 
534         rif->fd.fd = fd;
535 
536         memset(&ifr, 0, sizeof(ifr));
537         strcpy(ifr.ifr_name, rif->ifname);
538 
539         if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
540                 perror("ioctl(SIOCGIFHWADDR)");
541                 return -1;
542         }
543 
544         memcpy(sll->sll_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
545         sll->sll_family = AF_PACKET;
546         sll->sll_protocol = htons(ETH_P_ARP);
547         sll->sll_pkttype = PACKET_BROADCAST;
548         sll->sll_hatype = ARPHRD_ETHER;
549         sll->sll_halen = ETH_ALEN;
550 
551         if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
552                 perror("ioctl(SIOCGIFINDEX)");
553                 return -1;
554         }
555 
556         sll->sll_ifindex = ifr.ifr_ifindex;
557 
558         if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
559                 memcpy(rif->src_ip, DUMMY_IP, sizeof(rif->src_ip));
560         } else {
561                 sin = (struct sockaddr_in *) &ifr.ifr_addr;
562                 memcpy(rif->src_ip, &sin->sin_addr.s_addr, sizeof(rif->src_ip));
563         }
564 
565         if (bind(fd, (struct sockaddr *)sll, sizeof(struct sockaddr_ll)) < 0) {
566                 perror("bind(ETH_P_ARP)");
567                 return -1;
568         }
569 
570         rif->fd.cb = recv_packet;
571         uloop_fd_add(&rif->fd, ULOOP_READ | ULOOP_EDGE_TRIGGER);
572 
573         if (!forward_bcast && !forward_dhcp)
574                 return 0;
575 
576         fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP));
577         if (fd < 0)
578                 return 0;
579 
580         rif->bcast_fd.fd = fd;
581         rif->bcast_fd.cb = recv_bcast_packet;
582 
583         memcpy(&rif->bcast_sll, &rif->sll, sizeof(rif->bcast_sll));
584         sll = &rif->bcast_sll;
585         sll->sll_protocol = htons(ETH_P_IP);
586 
587         if (bind(fd, (struct sockaddr *)sll, sizeof(struct sockaddr_ll)) < 0) {
588                 perror("bind(ETH_P_IP)");
589                 return 0;
590         }
591 
592 #ifdef PACKET_RECV_TYPE
593         pkt_type = (1 << PACKET_BROADCAST) | (1 << PACKET_MULTICAST);
594         setsockopt(fd, SOL_PACKET, PACKET_RECV_TYPE, &pkt_type, sizeof(pkt_type));
595 #endif
596 
597         uloop_fd_add(&rif->bcast_fd, ULOOP_READ | ULOOP_EDGE_TRIGGER);
598         relayd_add_interface_routes(rif);
599         return 0;
600 }
601 
602 static void ping_static_routes(void)
603 {
604         struct relayd_pending_route *rt;
605         struct relayd_interface *rif;
606 
607         list_for_each_entry(rt, &pending_routes, rt.list)
608                 list_for_each_entry(rif, &interfaces, list)
609                         send_arp_request(rif, rt->gateway);
610 }
611 
612 static int init_interfaces(void)
613 {
614         struct relayd_interface *rif;
615         int ret;
616 
617         list_for_each_entry(rif, &interfaces, list) {
618                 ret = init_interface(rif);
619                 if (ret < 0)
620                         return ret;
621         }
622 
623         return 0;
624 }
625 
626 static void cleanup_hosts(void)
627 {
628         struct relayd_interface *rif;
629         struct relayd_host *host, *tmp;
630 
631         list_for_each_entry(rif, &interfaces, list) {
632                 list_for_each_entry_safe(host, tmp, &rif->hosts, list) {
633                         del_host(host);
634                 }
635         }
636 }
637 
638 static void free_interfaces(void)
639 {
640         struct relayd_interface *rif, *rtmp;
641 
642         list_for_each_entry_safe(rif, rtmp, &interfaces, list) {
643                 relayd_del_interface_routes(rif);
644                 list_del(&rif->list);
645                 free(rif);
646         }
647 }
648 
649 static struct relayd_interface *alloc_interface(const char *ifname, bool managed)
650 {
651         struct relayd_interface *rif;
652 
653         if (strlen(ifname) >= IFNAMSIZ)
654                 return NULL;
655 
656         list_for_each_entry(rif, &interfaces, list) {
657                 if (!strncmp(rif->ifname, ifname, IFNAMSIZ))
658                         return rif;
659         }
660 
661         rif = calloc(1, sizeof(*rif));
662         if (!rif)
663                 return NULL;
664 
665         INIT_LIST_HEAD(&rif->hosts);
666         strcpy(rif->ifname, ifname);
667         list_add(&rif->list, &interfaces);
668         rif->managed = managed;
669 
670         return rif;
671 }
672 
673 static void die(int signo)
674 {
675         /*
676          * When we hit SIGTERM, clean up interfaces directly, so that we
677          * won't leave our routing in an invalid state.
678          */
679         uloop_end();
680 }
681 
682 static int usage(const char *progname)
683 {
684         fprintf(stderr, "Usage: %s <options>\n"
685                         "\n"
686                         "Options:\n"
687                         "       -d              Enable debug messages\n"
688                         "       -i <ifname>     Add an interface for relaying\n"
689                         "       -I <ifname>     Same as -i, except with ARP cache and host route management\n"
690                         "                       You need to specify at least two interfaces\n"
691                         "       -G <ip>         Set a gateway IP for clients\n"
692                         "       -R <gateway>:<net>/<mask>\n"
693                         "                       Add a static route for <net>/<mask> via <gateway>\n"
694                         "       -t <timeout>    Host entry expiry timeout\n"
695                         "       -p <tries>      Number of ARP ping attempts before considering a host dead\n"
696                         "       -T <table>      Set routing table number for automatically added routes\n"
697                         "       -B              Enable broadcast forwarding\n"
698                         "       -D              Enable DHCP forwarding\n"
699                         "       -P              Disable DHCP options parsing\n"
700                         "       -L <ipaddr>     Enable local access using <ipaddr> as source address\n"
701                         "\n",
702                 progname);
703         return -1;
704 }
705 
706 int main(int argc, char **argv)
707 {
708         struct relayd_interface *rif = NULL;
709         struct in_addr addr, addr2;
710         bool local_addr_valid = false;
711         bool managed = false;
712         int ifnum = 0;
713         char *s, *s2;
714         int mask;
715         int ch;
716 
717         debug = 0;
718         inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
719         if (inet_sock < 0) {
720                 perror("socket(AF_INET)");
721                 return 1;
722         }
723 
724         host_timeout = 30;
725         host_ping_tries = 5;
726         forward_bcast = 0;
727         local_route_table = 0;
728         parse_dhcp = 1;
729         uloop_init();
730 
731         while ((ch = getopt(argc, argv, "I:i:t:p:BDPdT:G:R:L:")) != -1) {
732                 switch(ch) {
733                 case 'I':
734                         managed = true;
735                         /* fall through */
736                 case 'i':
737                         ifnum++;
738                         rif = alloc_interface(optarg, managed);
739                         if (!rif)
740                                 return 1;
741 
742                         managed = false;
743                         break;
744                 case 't':
745                         host_timeout = atoi(optarg);
746                         if (host_timeout <= 0)
747                                 return usage(argv[0]);
748                         break;
749                 case 'p':
750                         host_ping_tries = atoi(optarg);
751                         if (host_ping_tries <= 0)
752                                 return usage(argv[0]);
753                         break;
754                 case 'd':
755                         debug++;
756                         break;
757                 case 'B':
758                         forward_bcast = 1;
759                         break;
760                 case 'D':
761                         forward_dhcp = 1;
762                         break;
763                 case 'P':
764                         parse_dhcp = 0;
765                         break;
766                 case 'T':
767                         route_table = atoi(optarg);
768                         if (route_table <= 0)
769                                 return usage(argv[0]);
770                         break;
771                 case 'G':
772                         if (!inet_aton(optarg, &addr)) {
773                                 fprintf(stderr, "Address '%s' not found\n", optarg);
774                                 return 1;
775                         }
776                         relayd_add_pending_route((uint8_t *) &addr.s_addr, (const uint8_t *) "\x00\x00\x00\x00", 0, 0);
777                         break;
778                 case 'L':
779                         if (!inet_aton(optarg, &addr)) {
780                                 fprintf(stderr, "Address '%s' not found\n", optarg);
781                                 return 1;
782                         }
783                         memcpy(&local_addr, &addr.s_addr, sizeof(local_addr));
784                         local_addr_valid = true;
785                         break;
786                 case 'R':
787                         s = strchr(optarg, ':');
788                         if (!s)
789                                 return usage(argv[0]);
790 
791                         *(s++) = 0;
792                         if (!inet_aton(optarg, &addr)) {
793                                 fprintf(stderr, "Address '%s' not found\n", optarg);
794                                 return 1;
795                         }
796 
797                         s2 = strchr(s, '/');
798                         if (!s2)
799                                 return usage(argv[0]);
800 
801                         *(s2++) = 0;
802                         if (!inet_aton(s, &addr2)) {
803                                 fprintf(stderr, "Address '%s' not found\n", s);
804                                 return 1;
805                         }
806 
807                         mask = atoi(s2);
808                         if (mask < 0 || mask > 32)
809                                 return usage(argv[0]);
810 
811                         relayd_add_pending_route((uint8_t *) &addr.s_addr, (uint8_t *) &addr2.s_addr, mask, 0);
812                         break;
813                 case '?':
814                 default:
815                         return usage(argv[0]);
816                 }
817         }
818 
819         if (list_empty(&interfaces))
820                 return usage(argv[0]);
821 
822         if (ifnum < 2) {
823                 fprintf(stderr, "ERROR: Need at least 2 interfaces for relaying\n");
824                 return -1;
825         }
826 
827         argc -= optind;
828         argv += optind;
829 
830         signal(SIGTERM, die);
831         signal(SIGHUP, die);
832         signal(SIGUSR1, die);
833         signal(SIGUSR2, die);
834 
835         if (local_addr_valid)
836                 local_route_table = route_table++;
837 
838         if (relayd_rtnl_init() < 0)
839                 return 1;
840 
841         if (init_interfaces() < 0)
842                 return 1;
843 
844         ping_static_routes();
845 
846         uloop_run();
847         uloop_done();
848 
849         cleanup_hosts();
850         free_interfaces();
851         relayd_rtnl_done();
852         close(inet_sock);
853 
854         return 0;
855 }
856 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt