📄 kernel_routes.c
字号:
/* * The olsr.org Optimized Link-State Routing daemon(olsrd) * Copyright (c) 2004, Andreas T鴑nesen(andreto@olsr.org) * Copyright (c) 2007, Sven-Ola for the policy routing stuff * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of olsr.org, olsrd nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Visit http://www.olsr.org for more information. * * If you find this software useful feel free to make a donation * to the project. For more information see the website or contact * the copyright holders. * * $Id: kernel_routes.c,v 1.29 2007/10/13 12:31:04 bernd67 Exp $ */#include "kernel_routes.h"#include "ipc_frontend.h"#if !LINUX_POLICY_ROUTING#include "log.h"static int delete_all_inet_gws(void);#else /* !LINUX_POLICY_ROUTING */#include <assert.h>#include <linux/types.h>#include <linux/rtnetlink.h>struct olsr_rtreq{ struct nlmsghdr n; struct rtmsg r; char buf[512];};static void olsr_netlink_addreq(struct olsr_rtreq *req, int type, void *data, int len){ struct rtattr *rta = (struct rtattr*)(((char*)req) + NLMSG_ALIGN(req->n.nlmsg_len)); req->n.nlmsg_len = NLMSG_ALIGN(req->n.nlmsg_len) + RTA_LENGTH(len); assert(req->n.nlmsg_len < sizeof(struct olsr_rtreq)); rta->rta_type = type; rta->rta_len = RTA_LENGTH(len); memcpy(RTA_DATA(rta), data, len);}static int olsr_netlink_route(struct rt_entry *rt, olsr_u8_t family, olsr_u8_t rttable, __u16 cmd){ int ret = 0; struct olsr_rtreq req; struct iovec iov; struct sockaddr_nl nladdr; struct msghdr msg = { &nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; olsr_u32_t metric = 1; struct rt_nexthop* nexthop = (RTM_NEWROUTE == cmd) ? &rt->rt_best->rtp_nexthop : &rt->rt_nexthop; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; req.n.nlmsg_type = cmd; req.r.rtm_family = family; req.r.rtm_table = rttable; req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_scope = RT_SCOPE_LINK; req.r.rtm_type = RTN_UNICAST; req.r.rtm_dst_len = rt->rt_dst.prefix_len; if (AF_INET == family) { if (rt->rt_dst.prefix.v4 != nexthop->gateway.v4) { olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v4, sizeof(nexthop->gateway.v4)); req.r.rtm_scope = RT_SCOPE_UNIVERSE; metric = RT_METRIC_DEFAULT; } olsr_netlink_addreq(&req, RTA_DST, &rt->rt_dst.prefix.v4, sizeof(rt->rt_dst.prefix.v4)); } else { if (0 != memcmp(&rt->rt_dst.prefix.v6, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6))) { olsr_netlink_addreq(&req, RTA_GATEWAY, &nexthop->gateway.v6, sizeof(nexthop->gateway.v6)); req.r.rtm_scope = RT_SCOPE_UNIVERSE; metric = RT_METRIC_DEFAULT; } olsr_netlink_addreq(&req, RTA_DST, &rt->rt_dst.prefix.v6, sizeof(rt->rt_dst.prefix.v6)); } //!!!olsr_netlink_addreq(&req, RTA_PRIORITY, &rt->rt_best->rtp_metric.hops, sizeof(rt->rt_best->rtp_metric.hops)); olsr_netlink_addreq(&req, RTA_PRIORITY, &metric, sizeof(metric)); olsr_netlink_addreq(&req, RTA_OIF, &nexthop->iif_index, sizeof(nexthop->iif_index)); iov.iov_base = &req.n; iov.iov_len = req.n.nlmsg_len; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; if (0 <= (ret = sendmsg(olsr_cnf->rtnl_s, &msg, 0))) { iov.iov_base = req.buf; iov.iov_len = sizeof(req.buf); if (0 < (ret = recvmsg(olsr_cnf->rtnl_s, &msg, 0))) { struct nlmsghdr* h = (struct nlmsghdr*)req.buf; while (NLMSG_OK(h, (unsigned int)ret)) { if (NLMSG_DONE == h->nlmsg_type) break; if (NLMSG_ERROR == h->nlmsg_type) { if (NLMSG_LENGTH(sizeof(struct nlmsgerr) <= h->nlmsg_len)) { struct nlmsgerr *l_err = (struct nlmsgerr*)NLMSG_DATA(h); errno = -l_err->error; if (0 != errno) ret = -1; } break; } h = NLMSG_NEXT(h, ret); } } if (0 <= ret && olsr_cnf->open_ipc) { ipc_route_send_rtentry( &rt->rt_dst.prefix, &nexthop->gateway, metric, RTM_NEWROUTE == cmd, if_ifwithindex_name(nexthop->iif_index)); } } return ret;}#endif /* LINUX_POLICY_ROUTING *//** * Insert a route in the kernel routing table * * @param destination the route to add * * @return negative on error */intolsr_ioctl_add_route(struct rt_entry *rt){#if !LINUX_POLICY_ROUTING struct rtentry kernel_route; union olsr_ip_addr mask; int rslt;#endif /* LINUX_POLICY_ROUTING */ OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best));#if !LINUX_POLICY_ROUTING memset(&kernel_route, 0, sizeof(struct rtentry)); ((struct sockaddr_in*)&kernel_route.rt_dst)->sin_family = AF_INET; ((struct sockaddr_in*)&kernel_route.rt_gateway)->sin_family = AF_INET; ((struct sockaddr_in*)&kernel_route.rt_genmask)->sin_family = AF_INET; ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = rt->rt_dst.prefix.v4; if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) { return -1; } ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = mask.v4; if (rt->rt_dst.prefix.v4 != rt->rt_best->rtp_nexthop.gateway.v4) { ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr.s_addr = rt->rt_best->rtp_nexthop.gateway.v4; } kernel_route.rt_flags = olsr_rt_flags(rt); kernel_route.rt_metric = RT_METRIC_DEFAULT; /* * Set interface */ kernel_route.rt_dev = if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index); /* delete existing default route before ? */ if((olsr_cnf->del_gws) && (rt->rt_dst.prefix.v4 == INADDR_ANY) && (rt->rt_dst.prefix_len == INADDR_ANY)) { delete_all_inet_gws(); olsr_cnf->del_gws = OLSR_FALSE; } if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) { /* * Send IPC route update message */ ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1, if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index)); } return rslt;#else /* !LINUX_POLICY_ROUTING */ if (0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) { /* * Users start whining about not having internet with policy * routing activated and no static default route in table 254. * We maintain a fallback defroute in the default=253 table. */ olsr_netlink_route(rt, AF_INET, 253, RTM_NEWROUTE); } return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_NEWROUTE);#endif /* LINUX_POLICY_ROUTING */}/** *Insert a route in the kernel routing table * *@param destination the route to add * *@return negative on error */intolsr_ioctl_add_route6(struct rt_entry *rt){#if !LINUX_POLICY_ROUTING struct in6_rtmsg kernel_route; int rslt; OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best)); memset(&kernel_route, 0, sizeof(struct in6_rtmsg)); COPY_IP(&kernel_route.rtmsg_dst, &rt->rt_dst.prefix); kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len; COPY_IP(&kernel_route.rtmsg_gateway, &rt->rt_best->rtp_nexthop.gateway); kernel_route.rtmsg_flags = olsr_rt_flags(rt); kernel_route.rtmsg_metric = RT_METRIC_DEFAULT; /* * set interface */ kernel_route.rtmsg_ifindex = rt->rt_best->rtp_nexthop.iif_index; /* XXX delete 0/0 route before ? */ if((rslt = ioctl(olsr_cnf->ioctl_s, SIOCADDRT, &kernel_route)) >= 0) { /* * Send IPC route update message */ ipc_route_send_rtentry(&rt->rt_dst.prefix, &rt->rt_best->rtp_nexthop.gateway, rt->rt_best->rtp_metric.hops, 1, if_ifwithindex_name(rt->rt_best->rtp_nexthop.iif_index)); } return rslt;#else /* !LINUX_POLICY_ROUTING */ return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_NEWROUTE);#endif /* LINUX_POLICY_ROUTING */}/** *Remove a route from the kernel * *@param destination the route to remove * *@return negative on error */intolsr_ioctl_del_route(struct rt_entry *rt){#if !LINUX_POLICY_ROUTING struct rtentry kernel_route; union olsr_ip_addr mask; int rslt;#endif /* LINUX_POLICY_ROUTING */ OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));#if !LINUX_POLICY_ROUTING memset(&kernel_route,0,sizeof(struct rtentry)); ((struct sockaddr_in*)&kernel_route.rt_dst)->sin_family = AF_INET; ((struct sockaddr_in*)&kernel_route.rt_gateway)->sin_family = AF_INET; ((struct sockaddr_in*)&kernel_route.rt_genmask)->sin_family = AF_INET; ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = rt->rt_dst.prefix.v4; if (rt->rt_dst.prefix.v4 != rt->rt_nexthop.gateway.v4) { ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr.s_addr = rt->rt_nexthop.gateway.v4; } if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) { return -1; } else { ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = mask.v4; } kernel_route.rt_flags = olsr_rt_flags(rt); kernel_route.rt_metric = RT_METRIC_DEFAULT; /* * Set interface */ kernel_route.rt_dev = NULL; if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route)) >= 0) { /* * Send IPC route update message */ ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL); } return rslt;#else /* !LINUX_POLICY_ROUTING */ if (0 == rt->rt_dst.prefix_len && 253 > olsr_cnf->rttable) { /* * Also remove the fallback default route */ olsr_netlink_route(rt, AF_INET, 253, RTM_DELROUTE); } return olsr_netlink_route(rt, AF_INET, olsr_cnf->rttable, RTM_DELROUTE);#endif /* LINUX_POLICY_ROUTING */}/** *Remove a route from the kernel * *@param destination the route to remove * *@return negative on error */intolsr_ioctl_del_route6(struct rt_entry *rt){#if !LINUX_POLICY_ROUTING struct in6_rtmsg kernel_route; int rslt;#endif /* LINUX_POLICY_ROUTING */ OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt));#if !LINUX_POLICY_ROUTING memset(&kernel_route,0,sizeof(struct in6_rtmsg)); COPY_IP(&kernel_route.rtmsg_dst, &rt->rt_dst.prefix); kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len; COPY_IP(&kernel_route.rtmsg_gateway, &rt->rt_best->rtp_nexthop.gateway); kernel_route.rtmsg_flags = olsr_rt_flags(rt); kernel_route.rtmsg_metric = RT_METRIC_DEFAULT; if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route) >= 0)) { /* * Send IPC route update message */ ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL); } return rslt;#else /* !LINUX_POLICY_ROUTING */ return olsr_netlink_route(rt, AF_INET6, olsr_cnf->rttable, RTM_DELROUTE);#endif /* LINUX_POLICY_ROUTING */}#if !LINUX_POLICY_ROUTINGstatic int delete_all_inet_gws(void){ int s; char buf[BUFSIZ], *cp, *cplim; struct ifconf ifc; struct ifreq *ifr; OLSR_PRINTF(1, "Internet gateway detected...\nTrying to delete default gateways\n"); /* Get a socket */ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { olsr_syslog(OLSR_LOG_ERR, "socket: %m"); return -1; } ifc.ifc_len = sizeof (buf); ifc.ifc_buf = buf; if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { olsr_syslog(OLSR_LOG_ERR, "ioctl (get interface configuration)"); close(s); return -1; } ifr = ifc.ifc_req; cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */ for (cp = buf; cp < cplim; cp += sizeof (ifr->ifr_name) + sizeof(ifr->ifr_addr)) { struct rtentry kernel_route; ifr = (struct ifreq *)cp; if(strcmp(ifr->ifr_ifrn.ifrn_name, "lo") == 0) { OLSR_PRINTF(1, "Skipping loopback...\n"); continue; } OLSR_PRINTF(1, "Trying 0.0.0.0/0 %s...", ifr->ifr_ifrn.ifrn_name); memset(&kernel_route,0,sizeof(struct rtentry)); ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr.s_addr = 0; ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family=AF_INET; ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr.s_addr = 0; ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family=AF_INET; ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr.s_addr = INADDR_ANY; ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family=AF_INET; kernel_route.rt_flags = RTF_UP | RTF_GATEWAY; kernel_route.rt_dev = ifr->ifr_ifrn.ifrn_name; if((ioctl(s, SIOCDELRT, &kernel_route)) < 0) OLSR_PRINTF(1, "NO\n"); else OLSR_PRINTF(1, "YES\n"); } close(s); return 0; }#endif /* LINUX_POLICY_ROUTING *//* * Local Variables: * c-basic-offset: 2 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -