Remove the olsr-specific duplicated types
[olsrd.git] / src / linux / kernel_routes.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
4  * Copyright (c) 2007, Sven-Ola for the policy routing stuff
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without 
8  * modification, are permitted provided that the following conditions 
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright 
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright 
14  *   notice, this list of conditions and the following disclaimer in 
15  *   the documentation and/or other materials provided with the 
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its 
18  *   contributors may be used to endorse or promote products derived 
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include "kernel_routes.h"
43 #include "ipc_frontend.h"
44
45
46 #if !LINUX_POLICY_ROUTING
47 #include <unistd.h>
48 #include "log.h"
49 #include "process_routes.h"
50 #include "routing_table.h"
51
52 static int delete_all_inet_gws(void);
53
54 #else /* !LINUX_POLICY_ROUTING */
55
56 #include <assert.h>
57 #include <errno.h>
58 #include <linux/types.h>
59 #include <linux/rtnetlink.h>
60
61 struct olsr_rtreq {
62   struct nlmsghdr n;
63   struct rtmsg    r;
64   char            buf[512];
65 };
66
67 static void olsr_netlink_addreq(struct olsr_rtreq *req, int type, const void *data, int len)
68 {
69   struct rtattr *rta = (struct rtattr*)(((char*)req) + NLMSG_ALIGN(req->n.nlmsg_len));
70   req->n.nlmsg_len = NLMSG_ALIGN(req->n.nlmsg_len) + RTA_LENGTH(len);
71   assert(req->n.nlmsg_len < sizeof(*req));
72   rta->rta_type = type;
73   rta->rta_len = RTA_LENGTH(len);
74   memcpy(RTA_DATA(rta), data, len);
75 }
76
77 static int olsr_netlink_route(const struct rt_entry *rt, uint8_t family, uint8_t rttable, __u16 cmd)
78 {
79   int ret = 0;
80   struct olsr_rtreq req;
81   struct iovec iov;
82   struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
83   struct msghdr msg = {
84     .msg_name = &nladdr,
85     .msg_namelen = sizeof(nladdr),
86     .msg_iov = &iov,
87     .msg_iovlen = 1,
88     .msg_control = NULL,
89     .msg_controllen = 0,
90     .msg_flags = 0
91   };
92   uint32_t metric = FIBM_FLAT != olsr_cnf->fib_metric
93     ? (RTM_NEWROUTE == cmd
94        ? rt->rt_best->rtp_metric.hops
95        : rt->rt_metric.hops)
96     : RT_METRIC_DEFAULT;
97   const struct rt_nexthop* nexthop = RTM_NEWROUTE == cmd
98     ? &rt->rt_best->rtp_nexthop
99     : &rt->rt_nexthop;
100
101   memset(&req, 0, sizeof(req));
102   req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r));
103   req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
104   req.n.nlmsg_type = cmd;
105   req.r.rtm_family = family;
106   req.r.rtm_table = rttable;
107   req.r.rtm_protocol = RTPROT_BOOT;
108   req.r.rtm_scope = RT_SCOPE_LINK;
109   req.r.rtm_type = RTN_UNICAST;
110   req.r.rtm_dst_len = rt->rt_dst.prefix_len;
111
112   if (AF_INET == family) {
113     if (!ip4equal(&rt->rt_dst.prefix.v4, &nexthop->gateway.v4)) {
114       olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v4, sizeof(nexthop->gateway.v4));
115       req.r.rtm_scope = RT_SCOPE_UNIVERSE;
116     }
117     olsr_netlink_addreq(&req, RTA_DST, &rt->rt_dst.prefix.v4, sizeof(rt->rt_dst.prefix.v4));
118   } else {
119     if (!ip6equal(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6)) {
120       olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6));
121       req.r.rtm_scope = RT_SCOPE_UNIVERSE;
122     }
123     olsr_netlink_addreq(&req, RTA_DST, &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6));
124   }
125   if (FIBM_APPROX != olsr_cnf->fib_metric || RTM_NEWROUTE == cmd) {
126     olsr_netlink_addreq(&req, RTA_PRIORITY, &metric, sizeof(metric));
127   }
128   olsr_netlink_addreq(&req, RTA_OIF, &nexthop->iif_index, sizeof(nexthop->iif_index));
129   iov.iov_base = &req.n;
130   iov.iov_len = req.n.nlmsg_len;
131   ret = sendmsg(olsr_cnf->rtnl_s, &msg, 0);
132   if (0 <= ret) {
133     iov.iov_base = req.buf;
134     iov.iov_len = sizeof(req.buf);
135     ret = recvmsg(olsr_cnf->rtnl_s, &msg, 0);
136     if (0 < ret) {
137       struct nlmsghdr* h = (struct nlmsghdr*)req.buf;
138       while (NLMSG_OK(h, (unsigned int)ret)) {
139         if (NLMSG_DONE == h->nlmsg_type) {
140           break;
141         }
142         if (NLMSG_ERROR == h->nlmsg_type) {
143           if (NLMSG_LENGTH(sizeof(struct nlmsgerr) <= h->nlmsg_len)) {
144             const struct nlmsgerr *l_err = (struct nlmsgerr*)NLMSG_DATA(h);
145             errno = -l_err->error;
146             if (0 != errno) {
147               ret = -1;
148             }
149           }
150           break;
151         }
152         h = NLMSG_NEXT(h, ret);
153       }
154     }
155     if (0 <= ret && olsr_cnf->ipc_connections > 0) {
156       ipc_route_send_rtentry(&rt->rt_dst.prefix,
157                              &nexthop->gateway,
158                              metric,
159                              RTM_NEWROUTE == cmd,
160                              if_ifwithindex_name(nexthop->iif_index));
161     }
162   }
163   return ret;
164 }
165 #endif /* LINUX_POLICY_ROUTING */
166
167 /**
168  * Insert a route in the kernel routing table
169  *
170  * @param destination the route to add
171  *
172  * @return negative on error
173  */
174 int
175 olsr_ioctl_add_route(const struct rt_entry *rt)
176 {
177   int rslt;
178 #if !LINUX_POLICY_ROUTING
179   struct rtentry kernel_route;
180   union olsr_ip_addr mask;
181 #else /* !LINUX_POLICY_ROUTING */
182   int rttable;
183 #endif /* LINUX_POLICY_ROUTING */
184
185   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
186
187 #if !LINUX_POLICY_ROUTING
188   memset(&kernel_route, 0, sizeof(struct rtentry));
189
190   ((struct sockaddr_in*)&kernel_route.rt_dst)->sin_family = AF_INET;
191   ((struct sockaddr_in*)&kernel_route.rt_gateway)->sin_family = AF_INET;
192   ((struct sockaddr_in*)&kernel_route.rt_genmask)->sin_family = AF_INET;
193
194   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
195
196   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
197     return -1;
198   }
199   ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
200
201   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_best->rtp_nexthop.gateway.v4.s_addr) {
202     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr =
203       rt->rt_best->rtp_nexthop.gateway.v4;
204   }
205
206   kernel_route.rt_flags = olsr_rt_flags(rt);
207   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_best->rtp_metric);
208
209   /*
210    * Set interface
211    */
212   kernel_route.rt_dev = if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index);
213
214   /* delete existing default route before ? */
215   if((olsr_cnf->del_gws) &&
216      (rt->rt_dst.prefix.v4.s_addr == INADDR_ANY) &&
217      (rt->rt_dst.prefix_len == INADDR_ANY)) {
218     delete_all_inet_gws();
219     olsr_cnf->del_gws = false;
220   }
221
222   rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route);
223 #else /* !LINUX_POLICY_ROUTING */
224   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable)
225   {
226     /*
227      * Users start whining about not having internet with policy
228      * routing activated and no static default route in table 254.
229      * We maintain a fallback defroute in the default=253 table.
230      */
231     olsr_netlink_route(rt, AF_INET, 253, RTM_NEWROUTE);
232   }
233   rttable = 0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0
234     ? olsr_cnf->rttable_default
235     : olsr_cnf->rttable;
236   rslt = olsr_netlink_route(rt, AF_INET, rttable, RTM_NEWROUTE);
237 #endif /* LINUX_POLICY_ROUTING */
238
239   if (rslt >= 0) {
240     /*
241      * Send IPC route update message
242      */
243     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway,
244                            rt->rt_best->rtp_metric.hops, 1,
245                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
246   }
247   return rslt;
248 }
249
250
251 /**
252  *Insert a route in the kernel routing table
253  *
254  *@param destination the route to add
255  *
256  *@return negative on error
257  */
258 int
259 olsr_ioctl_add_route6(const struct rt_entry *rt)
260 {
261   int rslt;
262 #if !LINUX_POLICY_ROUTING
263   struct in6_rtmsg kernel_route;
264 #else /* !LINUX_POLICY_ROUTING */
265   int rttable;
266 #endif /* LINUX_POLICY_ROUTING */
267
268   OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));
269
270 #if !LINUX_POLICY_ROUTING
271   memset(&kernel_route, 0, sizeof(kernel_route));
272
273   kernel_route.rtmsg_dst     = rt->rt_dst.prefix.v6;
274   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
275
276   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
277
278   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
279   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric);
280   
281   /*
282    * set interface
283    */
284   kernel_route.rtmsg_ifindex = rt->rt_best->rtp_nexthop.iif_index;
285   
286   /* XXX delete 0/0 route before ? */
287   rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route);
288 #else /* !LINUX_POLICY_ROUTING */
289   rttable = 0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0
290     ? olsr_cnf->rttable_default
291     : olsr_cnf->rttable;
292   rslt = olsr_netlink_route(rt, AF_INET6, rttable, RTM_NEWROUTE);
293 #endif /* LINUX_POLICY_ROUTING */
294
295   if (rslt >= 0) {
296     /*
297      * Send IPC route update message
298      */
299     ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, 
300                            rt->rt_best->rtp_metric.hops, 1,
301                            if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index));
302   }
303
304   return rslt;
305 }
306
307
308 /**
309  *Remove a route from the kernel
310  *
311  *@param destination the route to remove
312  *
313  *@return negative on error
314  */
315 int
316 olsr_ioctl_del_route(const struct rt_entry *rt)
317 {
318   int rslt;
319 #if !LINUX_POLICY_ROUTING
320   struct rtentry kernel_route;
321   union olsr_ip_addr mask;
322 #else /* LINUX_POLICY_ROUTING */
323   int rttable;
324 #endif /* LINUX_POLICY_ROUTING */
325
326   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
327
328 #if !LINUX_POLICY_ROUTING
329   memset(&kernel_route,0,sizeof(struct rtentry));
330
331   ((struct sockaddr_in*)&kernel_route.rt_dst)->sin_family = AF_INET;
332   ((struct sockaddr_in*)&kernel_route.rt_gateway)->sin_family = AF_INET;
333   ((struct sockaddr_in*)&kernel_route.rt_genmask)->sin_family = AF_INET;
334
335   ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4;
336
337   if (rt->rt_dst.prefix.v4.s_addr != rt->rt_nexthop.gateway.v4.s_addr) {
338     ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_nexthop.gateway.v4;
339   }
340
341   if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) {
342     return -1;
343   } else {
344     ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4;
345   }
346
347   kernel_route.rt_flags = olsr_rt_flags(rt);
348   kernel_route.rt_metric = olsr_fib_metric(&rt->rt_metric);
349
350   /*
351    * Set interface
352    */
353   kernel_route.rt_dev = NULL;
354
355   rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route);
356 #else /* !LINUX_POLICY_ROUTING */
357   if (0 == olsr_cnf->rttable_default && 0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable)
358   {
359     /*
360      * Also remove the fallback default route
361      */
362     olsr_netlink_route(rt, AF_INET, 253, RTM_DELROUTE);
363   }
364   rttable = 0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0
365     ? olsr_cnf->rttable_default
366     : olsr_cnf->rttable;
367   rslt = olsr_netlink_route(rt, AF_INET, rttable, RTM_DELROUTE);
368 #endif /* LINUX_POLICY_ROUTING */
369   if (rslt >= 0) {
370
371     /*
372      * Send IPC route update message
373      */
374     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
375   }
376
377   return rslt;
378 }
379
380
381 /**
382  *Remove a route from the kernel
383  *
384  *@param destination the route to remove
385  *
386  *@return negative on error
387  */
388 int
389 olsr_ioctl_del_route6(const struct rt_entry *rt)
390 {
391   int rslt;
392 #if !LINUX_POLICY_ROUTING
393   struct in6_rtmsg kernel_route;
394 #else /* LINUX_POLICY_ROUTING */
395   int rttable;
396 #endif /* LINUX_POLICY_ROUTING */
397
398   OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));
399
400 #if !LINUX_POLICY_ROUTING
401   memset(&kernel_route, 0, sizeof(kernel_route));
402
403   kernel_route.rtmsg_dst     = rt->rt_dst.prefix.v6;
404   kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len;
405
406   kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6;
407
408   kernel_route.rtmsg_flags = olsr_rt_flags(rt);
409   kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric);
410
411   rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route);
412 #else /* !LINUX_POLICY_ROUTING */
413   rttable = 0 == rt->rt_dst.prefix_len && olsr_cnf->rttable_default != 0
414     ? olsr_cnf->rttable_default
415     : olsr_cnf->rttable;
416   rslt = olsr_netlink_route(rt, AF_INET6, rttable, RTM_DELROUTE);
417 #endif /* LINUX_POLICY_ROUTING */
418   if (rslt >= 0) {
419
420     /*
421      * Send IPC route update message
422      */
423     ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL);
424   }
425
426   return rslt;
427 }
428
429 #if !LINUX_POLICY_ROUTING
430 static int delete_all_inet_gws(void)
431 {  
432   int s;
433   char buf[BUFSIZ], *cp, *cplim;
434   struct ifconf ifc;
435   struct ifreq *ifr;
436   
437   OLSR_PRINTF(1, "Internet gateway detected...\nTrying to delete default gateways\n");
438   
439   /* Get a socket */
440   if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
441     {
442       olsr_syslog(OLSR_LOG_ERR, "socket: %m");
443       return -1;
444     }
445   
446   ifc.ifc_len = sizeof (buf);
447   ifc.ifc_buf = buf;
448   if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) 
449     {
450       olsr_syslog(OLSR_LOG_ERR, "ioctl (get interface configuration)");
451       close(s);
452       return -1;
453     }
454
455   ifr = ifc.ifc_req;
456   cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
457   for (cp = buf; cp < cplim; cp += sizeof (ifr->ifr_name) + sizeof(ifr->ifr_addr)) 
458     {
459       struct rtentry kernel_route;
460       ifr = (struct ifreq *)cp;
461       
462       
463       if(strcmp(ifr->ifr_ifrn.ifrn_name, "lo") == 0)
464         {
465           OLSR_PRINTF(1, "Skipping loopback...\n");
466           continue;
467         }
468
469       OLSR_PRINTF(1, "Trying 0.0.0.0/0 %s...", ifr->ifr_ifrn.ifrn_name);
470       
471       
472       memset(&kernel_route,0,sizeof(struct rtentry));
473       
474       ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = 0;
475       ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family=AF_INET;
476       ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = 0;
477       ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family=AF_INET;
478
479       ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr.s_addr = INADDR_ANY;
480       ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family=AF_INET;
481       
482
483       kernel_route.rt_flags = RTF_UP | RTF_GATEWAY;
484            
485       kernel_route.rt_dev = ifr->ifr_ifrn.ifrn_name;
486
487       if((ioctl(s, SIOCDELRT, &kernel_route)) < 0)
488          OLSR_PRINTF(1, "NO\n");
489       else
490          OLSR_PRINTF(1, "YES\n");
491     }  
492   close(s);
493   return 0;       
494 }
495 #endif /* LINUX_POLICY_ROUTING */
496
497 /*
498  * Local Variables:
499  * c-basic-offset: 2
500  * indent-tabs-mode: nil
501  * End:
502  */