From: Felix Fietkau Date: Fri, 27 Aug 2010 18:50:18 +0000 (+0200) Subject: implement local ip access through policy routing X-Git-Url: http://git.archive.openwrt.org/?p=project%2Frelayd.git;a=commitdiff_plain;h=ac87fbca7dbb82d8b09f19ea5588592b1ea10e4e implement local ip access through policy routing --- diff --git a/main.c b/main.c index 407c8c2..8fbbed2 100644 --- a/main.c +++ b/main.c @@ -40,6 +40,9 @@ static int inet_sock; static int forward_bcast; static int forward_dhcp; +uint8_t local_addr[4]; +int local_route_table; + struct relayd_pending_route { struct relayd_route rt; struct uloop_timeout timeout; @@ -641,6 +644,7 @@ static int usage(const char *progname) " -T Set routing table number for automatically added routes\n" " -B Enable broadcast forwarding\n" " -D Enable DHCP forwarding\n" + " -L Enable local access using as source address\n" "\n", progname); return -1; @@ -650,6 +654,7 @@ int main(int argc, char **argv) { struct relayd_interface *rif = NULL; struct in_addr addr, addr2; + bool local_addr_valid = false; bool managed; int ifnum = 0; char *s, *s2; @@ -665,9 +670,10 @@ int main(int argc, char **argv) host_timeout = 60; forward_bcast = 0; + local_route_table = 0; uloop_init(); - while ((ch = getopt(argc, argv, "I:i:t:BDdT:G:R:")) != -1) { + while ((ch = getopt(argc, argv, "I:i:t:BDdT:G:R:L:")) != -1) { switch(ch) { case 'I': managed = true; @@ -706,6 +712,14 @@ int main(int argc, char **argv) } relayd_add_pending_route((uint8_t *) &addr.s_addr, (const uint8_t *) "\x00\x00\x00\x00", 0, 0); break; + case 'L': + if (!inet_aton(optarg, &addr)) { + fprintf(stderr, "Address '%s' not found\n", optarg); + return 1; + } + memcpy(&local_addr, &addr.s_addr, sizeof(local_addr)); + local_addr_valid = true; + break; case 'R': s = strchr(optarg, ':'); if (!s) @@ -755,6 +769,9 @@ int main(int argc, char **argv) signal(SIGUSR1, die); signal(SIGUSR2, die); + if (local_addr_valid) + local_route_table = route_table++; + if (relayd_rtnl_init() < 0) return 1; diff --git a/relayd.h b/relayd.h index e21ca08..cd24aa6 100644 --- a/relayd.h +++ b/relayd.h @@ -100,6 +100,8 @@ struct rtnl_req { extern struct list_head interfaces; extern int debug; extern int route_table; +extern uint8_t local_addr[4]; +extern int local_route_table; void rtnl_route_set(struct relayd_host *host, struct relayd_route *route, bool add); diff --git a/route.c b/route.c index abe0263..cbb624e 100644 --- a/route.c +++ b/route.c @@ -47,6 +47,14 @@ enum { RULE_F_DEFGW_WORKAROUND = (1 << 1), }; +static int get_route_table(struct relayd_interface *rif) +{ + if (rif) + return rif->rt_table; + else + return local_route_table; +} + static void rtnl_rule_request(struct relayd_interface *rif, int flags) { @@ -73,21 +81,24 @@ rtnl_rule_request(struct relayd_interface *rif, int flags) .rta_len = sizeof(req.table), }, }; - + const char *ifname = "lo"; int padding = sizeof(req.dev.ifname); + if (rif) + ifname = rif->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; + padding -= strlen(ifname) + 1; + strcpy(req.dev.ifname, ifname); + req.dev.rta.rta_len = sizeof(req.dev.rta) + strlen(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.table.table = get_route_table(rif); req.nl.nlmsg_len = sizeof(req) - padding; req.nl.nlmsg_flags = NLM_F_REQUEST; @@ -105,6 +116,19 @@ rtnl_rule_request(struct relayd_interface *rif, int flags) rtnl_flush(); } +struct rtnl_addr { + struct rtattr rta; + uint8_t ipaddr[4]; +} __packed; + +static struct rtnl_addr * +rtnl_add_addr(struct rtnl_addr *addr, int *len, int type, const uint8_t *ipaddr) +{ + addr->rta.rta_type = type; + memcpy(addr->ipaddr, ipaddr, 4); + *len += sizeof(*addr); + return addr + 1; +} static void rtnl_route_request(struct relayd_interface *rif, struct relayd_host *host, @@ -115,20 +139,13 @@ rtnl_route_request(struct relayd_interface *rif, struct relayd_host *host, struct rtmsg rt; struct { struct rtattr rta; - uint8_t ipaddr[4]; - } __packed dst; - struct { - struct rtattr rta; int table; } __packed table; struct { struct rtattr rta; int ifindex; } __packed dev; - struct { - struct rtattr rta; - uint8_t ipaddr[4]; - } __packed gw; + struct rtnl_addr addr[3]; } __packed req = { .rt = { .rtm_family = AF_INET, @@ -139,22 +156,20 @@ rtnl_route_request(struct relayd_interface *rif, struct relayd_host *host, .rta_type = RTA_TABLE, .rta_len = sizeof(req.table), }, - .dst.rta = { - .rta_len = sizeof(req.dst), - }, .dev.rta = { .rta_type = RTA_OIF, .rta_len = sizeof(req.dev), }, - .gw.rta = { - .rta_type = RTA_GATEWAY, - .rta_len = sizeof(req.gw), - }, + .addr[0].rta.rta_len = sizeof(struct rtnl_addr), + .addr[1].rta.rta_len = sizeof(struct rtnl_addr), + .addr[2].rta.rta_len = sizeof(struct rtnl_addr), }; - int pktlen = sizeof(req); + int pktlen = sizeof(req) - sizeof(req.addr); + struct rtnl_addr *addr = &req.addr[0]; + const char *ifname = "loopback"; req.dev.ifindex = host->rif->sll.sll_ifindex; - req.table.table = rif->rt_table; + req.table.table = get_route_table(rif); req.nl.nlmsg_flags = NLM_F_REQUEST; if (add) { @@ -173,27 +188,29 @@ rtnl_route_request(struct relayd_interface *rif, struct relayd_host *host, req.rt.rtm_scope = RT_SCOPE_NOWHERE; } - req.dst.rta.rta_type = RTA_DST; + if (rif) + ifname = rif->ifname; + if (route) { - DPRINTF(2, "%s: add route to "IP_FMT"/%d via "IP_FMT"\n", - host->rif->ifname, IP_BUF(route->dest), route->mask, IP_BUF(host->ipaddr)); - if (!route->mask) { - /* No DST -> reuse the DST attribute as the gateway attribute */ - memcpy(req.dst.ipaddr, host->ipaddr, sizeof(req.dst.ipaddr)); - req.dst.rta.rta_type = RTA_GATEWAY; - pktlen -= sizeof(req.gw); - req.rt.rtm_dst_len = 0; - } else { - memcpy(req.gw.ipaddr, host->ipaddr, sizeof(req.gw.ipaddr)); - memcpy(req.dst.ipaddr, route->dest, sizeof(req.dst.ipaddr)); - req.rt.rtm_dst_len = route->mask; - } + DPRINTF(2, "%s: add route to "IP_FMT"/%d via "IP_FMT" (%s)\n", ifname, + IP_BUF(route->dest), route->mask, IP_BUF(host->ipaddr), + host->rif->ifname); + + req.rt.rtm_dst_len = route->mask; + if (route->mask) + addr = rtnl_add_addr(addr, &pktlen, RTA_DST, route->dest); + addr = rtnl_add_addr(addr, &pktlen, RTA_GATEWAY, host->ipaddr); } else { - pktlen -= sizeof(req.gw); + DPRINTF(2, "%s: add host route to "IP_FMT" (%s)\n", ifname, + IP_BUF(host->ipaddr), host->rif->ifname); + addr = rtnl_add_addr(addr, &pktlen, RTA_DST, host->ipaddr); req.rt.rtm_dst_len = 32; - memcpy(req.dst.ipaddr, host->ipaddr, sizeof(req.dst.ipaddr)); } + /* local route */ + if (!rif) + addr = rtnl_add_addr(addr, &pktlen, RTA_PREFSRC, local_addr); + req.nl.nlmsg_len = pktlen; if (route) rtnl_rule_request(rif, RULE_F_DEFGW_WORKAROUND | RULE_F_ADD); @@ -214,6 +231,8 @@ rtnl_route_set(struct relayd_host *host, struct relayd_route *route, bool add) rtnl_route_request(rif, host, route, add); } + if (local_route_table) + rtnl_route_request(NULL, host, route, add); } void relayd_add_interface_routes(struct relayd_interface *rif) @@ -372,12 +391,14 @@ int relayd_rtnl_init(void) rtnl_seq = time(NULL); rtnl_dump_seq = rtnl_seq; rtnl_dump_request(RTM_GETNEIGH); + rtnl_rule_request(NULL, RULE_F_ADD); return 0; } void relayd_rtnl_done(void) { + rtnl_rule_request(NULL, 0); uloop_fd_delete(&rtnl_sock); close(rtnl_sock.fd); }