From 78c5e4b032c420852abc2a9e1e6f429a4d803c21 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Mon, 14 Oct 2013 13:12:28 +0200 Subject: [PATCH] Various fixes --- README | 93 ++++++++++++++++++++++++++++++++++------------------ src/config.c | 19 ++++++++--- src/dhcpv4.c | 6 ++-- src/odhcpd.h | 1 + src/ubus.c | 37 +++++++++++++++++++++ 5 files changed, 118 insertions(+), 38 deletions(-) diff --git a/README b/README index c1c0d1e..f81d260 100644 --- a/README +++ b/README @@ -21,8 +21,8 @@ prefix delegation and can be used to relay RA, DHCPv6 and NDP between routed relay: RD relay between master and slave interfaces a) support for rewriting announced DNS-server addresses in relay mode -3. DHCPv6-support with 2 modes of operation - server: minimalistic server mode +2. DHCPv6-support with 2 modes of operation + server: stateless, stateful and PD-server mode a) stateless and stateful address assignment b) prefix delegation support c) dynamic reconfiguration in case prefixes change @@ -31,6 +31,9 @@ prefix delegation and can be used to relay RA, DHCPv6 and NDP between routed relay: mostly standards-compliant DHCPv6-relay a) support for rewriting announced DNS-server addresses +3. DHCPv4-support + server: stateless and stateful mode + 4. Proxy for Neighbor Discovery messages (solicitations and advertisments) a) support for auto-learning routes to the local routing table b) support for marking interfaces "external" not proxying NDP for them @@ -46,40 +49,68 @@ odhcpd uses cmake: * To build DEB or RPM packages use: "make package" afterwards. -** Server Mode ** +** Configuration ** -0. Server mode is used as a minimalistic alternative for full-blown servers - like radvd or ISC DHCP if simplicity or a small footprint matter. - Note: The master interface is unused in this mode. It should be set to '.'. +odhcpd uses a UCI configuration file in /etc/config/dhcp for configuration +and may also receive information from ubus -1. If there are non-local addresses assigned to the slave interface when a - router solicitation is received, said prefixes are announced automatically - for stateless autoconfiguration and also offered via stateful DHCPv6. - If all prefixes are bigger than /64 all but the first /64 of these prefixes - is offered via DHCPv6-PD to downstream routers. -2. If DNS servers should be announced (DHCPv6 server-mode) then a local DNS- - proxy (e.g. dnsmasq) needs to be run on the router itself because 6relayd - will always announce a local address as DNS-server (if not otherwise - configured). +Section of type odhcpd -3. odhcpd is run with the appropriate configuration. +Option Type Default Description +legacy bool 0 Enable DHCPv4 if start but + no dhcpv4 option set +leasefile string DHCP/v6 lease/hostfile +leasetrigger string Lease trigger script -** Relay Mode ** +Sections of type dhcp (configure DHCP / DHCPv6 / RA / NDP service) -0. Relay mode is used when a /64-bit IPv6-Prefix should be distributed over - several links / isolated layer 2 domains (e.g. if no prefix delegation - is available). In this mode NDP (namely Router Discovery and Neighbor - Discovery) messages and DHCPv6-messages are proxied. For DHCPv6 also - server mode can be used instead of relaying if desired. +Option Type Default Description +interface string logical OpenWrt interface +ifname string physical network interface +networkid string same as ifname compat. alias for ifname +ignore bool 0 ignore this interface +master bool 0 is a master interface + for relaying + +ra string disabled Router Advert service + [disabled|server|relay|hybrid] +dhcpv6 string disabled DHCPv6 service + [disabled|server|relay|hybrid] +dhcpv4 string disabled DHCPv4 service + [disabled|server] +ndp string disabled Neighbor Discovery Proxy + [disabled|relay|hybrid] + +dynamicdhcp bool 1 dynamically create leases + for DHCPv4 and DHCPv6 +dns list DNS servers to announce + accepts IPv4 and IPv6 +domain list Search domains to announce + +leasetime string 12h DHCPv4 address leasetime +start integer 100 DHCPv4 pool start +limit integer 150 DHCPv4 pool size + +ula_compat bool 0 Announce ULA in compat mode +ra_default integer 0 Override default route + 0: default, 1: ignore no public address, 2: ignore all +ra_management integer 1 RA management mode + 0: no M-Flag but A-Flag, 1: both M and A, 2: M but not A +ra_offlink bool 0 Announce prefixes off-link +ra_preference string medium Route(r) preference + [medium|high|low] +ndproxy_routing bool 0 Learn routes from NDP +ndproxy_slave bool 0 NDProxy external slave +ndproxy_static list Static NDProxy prefixes + + +Sections of type lease (static leases) +Option Type Default Description +ip string IP-Address to lease +mac string MAC-address +duid string DUID in base16 +hostid string IPv6 host identifier +hostname string Hostname -1. When starting 6relayd it is required that the master interface - where - IPv6-service is already provided - is configured and usable. - -2. If the upstream router doesn't provide or announce a DNS-service that is - reachable in an at least site-local scope, a local DNS proxy (e.g. dnsmasq) - needs to be run and configued on the same router where 6relayd is running. - (This step can most likely be skipped in most environments.) - -3. odhcpd is run with the appropriate configuration. diff --git a/src/config.c b/src/config.c index 6ae219a..ebc6642 100644 --- a/src/config.c +++ b/src/config.c @@ -15,6 +15,7 @@ struct config config = {false, NULL, NULL}; enum { IFACE_ATTR_INTERFACE, IFACE_ATTR_IFNAME, + IFACE_ATTR_NETWORKID, IFACE_ATTR_DYNAMICDHCP, IFACE_ATTR_IGNORE, IFACE_ATTR_LEASETIME, @@ -25,7 +26,7 @@ enum { IFACE_ATTR_RA, IFACE_ATTR_DHCPV4, IFACE_ATTR_DHCPV6, - IFACE_ATTR_NDPROXY, + IFACE_ATTR_NDP, IFACE_ATTR_DNS, IFACE_ATTR_DOMAIN, IFACE_ATTR_ULA_COMPAT, @@ -42,6 +43,7 @@ enum { static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { [IFACE_ATTR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, + [IFACE_ATTR_NETWORKID] = { .name = "networkid", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_DYNAMICDHCP] = { .name = "dynamicdhcp", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_IGNORE] = { .name = "ignore", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_LEASETIME] = { .name = "leasetime", .type = BLOBMSG_TYPE_STRING }, @@ -52,7 +54,7 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { [IFACE_ATTR_RA] = { .name = "ra", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_DHCPV4] = { .name = "dhcpv4", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_DHCPV6] = { .name = "dhcpv6", .type = BLOBMSG_TYPE_STRING }, - [IFACE_ATTR_NDPROXY] = { .name = "ndproxy", .type = BLOBMSG_TYPE_BOOL }, + [IFACE_ATTR_NDP] = { .name = "ndp", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY }, [IFACE_ATTR_DOMAIN] = { .name = "domain", .type = BLOBMSG_TYPE_ARRAY }, [IFACE_ATTR_ULA_COMPAT] = { .name = "ula_compat", .type = BLOBMSG_TYPE_BOOL }, @@ -276,6 +278,8 @@ int config_parse_interface(struct blob_attr *b, const char *name, bool overwrite #endif if ((c = tb[IFACE_ATTR_IFNAME])) ifname = blobmsg_get_string(c); + else if ((c = tb[IFACE_ATTR_NETWORKID])) + ifname = blobmsg_get_string(c); strncpy(iface->ifname, ifname, sizeof(iface->ifname) - 1); iface->inuse = true; @@ -352,13 +356,15 @@ int config_parse_interface(struct blob_attr *b, const char *name, bool overwrite if ((iface->dhcpv6 = parse_mode(blobmsg_get_string(c))) < 0) goto err; - if ((c = tb[IFACE_ATTR_NDPROXY])) - iface->ndp = blobmsg_get_bool(c) ? RELAYD_RELAY : RELAYD_DISABLED; + if ((c = tb[IFACE_ATTR_NDP])) + if ((iface->ndp = parse_mode(blobmsg_get_string(c))) < 0) + goto err; if ((c = tb[IFACE_ATTR_DNS])) { struct blob_attr *cur; int rem; + iface->always_rewrite_dns = true; blobmsg_for_each_attr(cur, c, rem) { if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING || !blobmsg_check_attr(cur, NULL)) continue; @@ -513,6 +519,11 @@ void odhcpd_run(void) continue; enum odhcpd_mode hybrid_mode = RELAYD_DISABLED; +#ifdef WITH_UBUS + if (ubus_has_prefix(i->name, i->ifname)) + hybrid_mode = RELAYD_RELAY; +#endif + if (i->dhcpv6 == RELAYD_HYBRID) i->dhcpv6 = hybrid_mode; diff --git a/src/dhcpv4.c b/src/dhcpv4.c index 38b4f9b..7a68f66 100644 --- a/src/dhcpv4.c +++ b/src/dhcpv4.c @@ -119,8 +119,8 @@ int setup_dhcpv4_interface(struct interface *iface, bool enable) end = addr.s_addr & mask.s_addr; if (ntohl(mask.s_addr) <= 0xffffff00) { - iface->dhcpv4_start.s_addr = start | htonl(20); - iface->dhcpv4_end.s_addr = end | htonl(199); + iface->dhcpv4_start.s_addr = start | htonl(100); + iface->dhcpv4_end.s_addr = end | htonl(250); } else { iface->dhcpv4_start.s_addr = start | htonl(10); iface->dhcpv4_end.s_addr = end | htonl(59); @@ -168,7 +168,7 @@ int setup_dhcpv4_interface(struct interface *iface, bool enable) if (iface->dhcpv4_leasetime < 60) - iface->dhcpv4_leasetime = 1800; + iface->dhcpv4_leasetime = 43200; iface->dhcpv4_event.uloop.fd = sock; iface->dhcpv4_event.handle_dgram = handle_dhcpv4; diff --git a/src/odhcpd.h b/src/odhcpd.h index be8baeb..fb3db37 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -190,6 +190,7 @@ int config_parse_interface(struct blob_attr *b, const char *iname, bool overwrit const char* ubus_get_ifname(const char *name); void ubus_apply_network(void); +bool ubus_has_prefix(const char *name, const char *ifname); // Exported module initializers diff --git a/src/ubus.c b/src/ubus.c index 7f69d3d..41d538a 100644 --- a/src/ubus.c +++ b/src/ubus.c @@ -160,6 +160,7 @@ enum { IFACE_ATTR_IFNAME, IFACE_ATTR_UP, IFACE_ATTR_DATA, + IFACE_ATTR_PREFIX, IFACE_ATTR_MAX, }; @@ -168,6 +169,7 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = { [IFACE_ATTR_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, [IFACE_ATTR_UP] = { .name = "up", .type = BLOBMSG_TYPE_BOOL }, [IFACE_ATTR_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE }, + [IFACE_ATTR_PREFIX] = { .name = "ipv6-prefix", .type = BLOBMSG_TYPE_ARRAY }, }; static void handle_dump(_unused struct ubus_request *req, _unused int type, struct blob_attr *msg) @@ -308,6 +310,41 @@ const char* ubus_get_ifname(const char *name) } +bool ubus_has_prefix(const char *name, const char *ifname) +{ + struct blob_attr *c, *cur; + int rem; + + if (!dump) + return NULL; + + blobmsg_for_each_attr(c, dump, rem) { + struct blob_attr *tb[IFACE_ATTR_MAX]; + blobmsg_parse(iface_attrs, IFACE_ATTR_MAX, tb, blob_data(c), blob_len(c)); + + if (!tb[IFACE_ATTR_INTERFACE] || !tb[IFACE_ATTR_IFNAME]) + continue; + + if (!strcmp(name, blobmsg_get_string(tb[IFACE_ATTR_INTERFACE])) || + !strcmp(ifname, blobmsg_get_string(tb[IFACE_ATTR_IFNAME]))) + continue; + + if ((cur = tb[IFACE_ATTR_PREFIX])) { + if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY || !blobmsg_check_attr(cur, NULL)) + continue; + + struct blob_attr *d; + int drem; + blobmsg_for_each_attr(d, cur, drem) { + return true; + } + } + } + + return false; +} + + int init_ubus(void) { if (!(ubus = ubus_connect(NULL))) { -- 2.25.1