X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=route.c;h=abe026310dfff7d6064c9a85bb799114e7895902;hb=82c536bbfca7d684fec1a363fb3119267bb98576;hp=25f949e3f27bbacdb5fcda626eabf6cd6e7b597b;hpb=000bd94557f07cea56b9d1d1b0c0328b8d17a507;p=oweals%2Frelayd.git diff --git a/route.c b/route.c index 25f949e..abe0263 100644 --- a/route.c +++ b/route.c @@ -42,6 +42,70 @@ static void rtnl_flush(void) close(fd); } +enum { + RULE_F_ADD = (1 << 0), + RULE_F_DEFGW_WORKAROUND = (1 << 1), +}; + +static void +rtnl_rule_request(struct relayd_interface *rif, int flags) +{ + static struct { + struct nlmsghdr nl; + struct rtmsg rt; + struct { + struct rtattr rta; + int table; + } __packed table; + struct { + struct rtattr rta; + char ifname[IFNAMSIZ + 1]; + } __packed dev; + } __packed req = { + .rt = { + .rtm_family = AF_INET, + .rtm_table = RT_TABLE_UNSPEC, + .rtm_scope = RT_SCOPE_UNIVERSE, + .rtm_protocol = RTPROT_BOOT, + }, + .table.rta = { + .rta_type = FRA_TABLE, + .rta_len = sizeof(req.table), + }, + }; + + int padding = sizeof(req.dev.ifname); + + if (!(flags & RULE_F_DEFGW_WORKAROUND)) { + req.dev.rta.rta_type = FRA_IFNAME; + padding -= strlen(rif->ifname) + 1; + strcpy(req.dev.ifname, rif->ifname); + req.dev.rta.rta_len = sizeof(req.dev.rta) + strlen(rif->ifname) + 1; + } else { + req.dev.rta.rta_type = FRA_PRIORITY; + req.dev.rta.rta_len = sizeof(req.dev.rta) + sizeof(uint32_t); + padding -= sizeof(uint32_t); + *((uint32_t *) &req.dev.ifname) = 1; + } + req.table.table = rif->rt_table; + req.nl.nlmsg_len = sizeof(req) - padding; + + req.nl.nlmsg_flags = NLM_F_REQUEST; + if (flags & RULE_F_ADD) { + req.nl.nlmsg_type = RTM_NEWRULE; + req.nl.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; + + req.rt.rtm_type = RTN_UNICAST; + } else { + req.nl.nlmsg_type = RTM_DELRULE; + req.rt.rtm_type = RTN_UNSPEC; + } + + send(rtnl_sock.fd, &req, req.nl.nlmsg_len, 0); + rtnl_flush(); +} + + static void rtnl_route_request(struct relayd_interface *rif, struct relayd_host *host, struct relayd_route *route, bool add) @@ -131,59 +195,11 @@ rtnl_route_request(struct relayd_interface *rif, struct relayd_host *host, } req.nl.nlmsg_len = pktlen; + if (route) + rtnl_rule_request(rif, RULE_F_DEFGW_WORKAROUND | RULE_F_ADD); send(rtnl_sock.fd, &req, pktlen, 0); - rtnl_flush(); -} - -static void rtnl_rule_request(struct relayd_interface *rif, bool add) -{ - static struct { - struct nlmsghdr nl; - struct rtmsg rt; - struct { - struct rtattr rta; - int table; - } __packed table; - struct { - struct rtattr rta; - char ifname[IFNAMSIZ + 1]; - } __packed dev; - } __packed req = { - .rt = { - .rtm_family = AF_INET, - .rtm_table = RT_TABLE_UNSPEC, - .rtm_scope = RT_SCOPE_UNIVERSE, - .rtm_protocol = RTPROT_BOOT, - }, - .table.rta = { - .rta_type = FRA_TABLE, - .rta_len = sizeof(req.table), - }, - .dev.rta = { - .rta_type = FRA_IFNAME, - }, - }; - - int padding = sizeof(req.dev.ifname); - padding -= strlen(rif->ifname) + 1; - - strcpy(req.dev.ifname, rif->ifname); - req.dev.rta.rta_len = sizeof(req.dev.rta) + strlen(rif->ifname) + 1; - req.table.table = rif->rt_table; - req.nl.nlmsg_len = sizeof(req) - padding; - - req.nl.nlmsg_flags = NLM_F_REQUEST; - if (add) { - req.nl.nlmsg_type = RTM_NEWRULE; - req.nl.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; - - req.rt.rtm_type = RTN_UNICAST; - } else { - req.nl.nlmsg_type = RTM_DELRULE; - req.rt.rtm_type = RTN_UNSPEC; - } - - send(rtnl_sock.fd, &req, req.nl.nlmsg_len, 0); + if (route) + rtnl_rule_request(rif, RULE_F_DEFGW_WORKAROUND); rtnl_flush(); } @@ -203,12 +219,12 @@ rtnl_route_set(struct relayd_host *host, struct relayd_route *route, bool add) void relayd_add_interface_routes(struct relayd_interface *rif) { rif->rt_table = route_table++; - rtnl_rule_request(rif, true); + rtnl_rule_request(rif, RULE_F_ADD); } void relayd_del_interface_routes(struct relayd_interface *rif) { - rtnl_rule_request(rif, false); + rtnl_rule_request(rif, 0); } #ifndef NDA_RTA @@ -313,21 +329,28 @@ static void rtnl_cb(struct uloop_fd *fd, unsigned int events) } while (1); } -int relayd_rtnl_init(void) +static void rtnl_dump_request(int nlmsg_type) { - struct sockaddr_nl snl_local; static struct { struct nlmsghdr nlh; struct rtgenmsg g; } req = { .nlh = { .nlmsg_len = sizeof(req), - .nlmsg_type = RTM_GETNEIGH, .nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST, .nlmsg_pid = 0, }, .g.rtgen_family = AF_INET, }; + req.nlh.nlmsg_type = nlmsg_type; + req.nlh.nlmsg_seq = rtnl_seq; + send(rtnl_sock.fd, &req, sizeof(req), 0); + rtnl_seq++; +} + +int relayd_rtnl_init(void) +{ + struct sockaddr_nl snl_local; rtnl_sock.fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (rtnl_sock.fd < 0) { @@ -348,8 +371,7 @@ int relayd_rtnl_init(void) rtnl_seq = time(NULL); rtnl_dump_seq = rtnl_seq; - req.nlh.nlmsg_seq = rtnl_seq; - send(rtnl_sock.fd, &req, sizeof(req), 0); + rtnl_dump_request(RTM_GETNEIGH); return 0; }