diff options
38 files changed, 2191 insertions, 816 deletions
diff --git a/libexec/rtld-elf/Makefile b/libexec/rtld-elf/Makefile index 95bec19..45318b9 100644 --- a/libexec/rtld-elf/Makefile +++ b/libexec/rtld-elf/Makefile @@ -17,7 +17,6 @@ RTLD_ARCH= ${MACHINE_CPUARCH} .endif CFLAGS+= -I${.CURDIR}/${RTLD_ARCH} -I${.CURDIR} .if ${MACHINE_ARCH} == "powerpc64" -CFLAGS+= -mcall-aixdesc LDFLAGS+= -nostdlib -e _rtld_start .else LDFLAGS+= -nostdlib -e .rtld_start diff --git a/libexec/ypxfr/ypxfr_extern.h b/libexec/ypxfr/ypxfr_extern.h index f843b64..2712bb9 100644 --- a/libexec/ypxfr/ypxfr_extern.h +++ b/libexec/ypxfr/ypxfr_extern.h @@ -44,7 +44,7 @@ extern BTREEINFO openinfo_b; #define _PATH_YP "/var/yp/" #endif -extern char *yp_dir; +extern const char *yp_dir; extern int debug; extern enum ypstat yp_errno; extern void yp_error(const char *, ...); diff --git a/libexec/ypxfr/ypxfr_main.c b/libexec/ypxfr/ypxfr_main.c index f6b478a..636bc3d 100644 --- a/libexec/ypxfr/ypxfr_main.c +++ b/libexec/ypxfr/ypxfr_main.c @@ -51,8 +51,8 @@ __FBSDID("$FreeBSD$"); #include <rpcsvc/ypxfrd.h> #include "ypxfr_extern.h" -char *progname = "ypxfr"; -char *yp_dir = _PATH_YP; +const char *progname = "ypxfr"; +const char *yp_dir = _PATH_YP; int _rpcpmstart = 0; int ypxfr_use_yplib = 0; /* Assume the worst. */ int ypxfr_clear = 1; diff --git a/release/ia64/mkisoimages.sh b/release/ia64/mkisoimages.sh index f17185b..8709c12 100644 --- a/release/ia64/mkisoimages.sh +++ b/release/ia64/mkisoimages.sh @@ -74,6 +74,6 @@ fi echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > $BASE/etc/fstab makefs -t cd9660 $BOOTOPTS -o rockridge -o label=$LABEL $NAME $BASE $* -rm $BASE/etc/fstab rm -f $EFIPART +rm $1/etc/fstab exit 0 diff --git a/share/man/man4/stf.4 b/share/man/man4/stf.4 index 660e33e..fb2617a 100644 --- a/share/man/man4/stf.4 +++ b/share/man/man4/stf.4 @@ -1,6 +1,7 @@ .\" $KAME: stf.4,v 1.35 2001/05/02 06:24:49 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. +.\" Copyright (c) 2010 Hiroki Sato <hrs@FreeBSD.org> .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -29,7 +30,7 @@ .\" .\" $FreeBSD$ .\" -.Dd April 27, 2001 +.Dd September 23, 2010 .Dt STF 4 .Os .Sh NAME @@ -42,21 +43,11 @@ tunnel interface .Sh DESCRIPTION The .Nm -interface supports -.Dq 6to4 -IPv6 in IPv4 encapsulation. -It can tunnel IPv6 traffic over IPv4, as specified in -.Li RFC3056 . -.Pp -For ordinary nodes in 6to4 site, you do not need -.Nm -interface. -The -.Nm -interface is necessary for site border router -(called -.Dq 6to4 router -in the specification). +interface supports IPv6 in IPv4 encapsulation by +tunneling IPv6 traffic over IPv4, as specified in +.Li RFC3056 Pq 6to4 +and +.Li RFC5569 Pq 6rd . .Pp Each .Nm @@ -72,12 +63,28 @@ variable in .Pp Due to the way 6to4 protocol is specified, .Nm -interface requires certain configuration to work properly. +interface requires certain configuration to work properly. Two +different protocols defined in RFC3056 and RFC5569 are basically the +same as each other except for address handling, so +.Nm +decides its behavior based on the configured IPv6 addresses as +explained in the following. +The +.Nm +interface can be configured with multiple IPv6 addresses including +both 6to4 and 6rd. +.Sh RFC3056 (a.k.a. 6to4) Single -(no more than 1) -valid 6to4 address needs to be configured to the interface. -.Dq A valid 6to4 address -is an address which has the following properties. +.Pq no more than 1 valid 6to4 address needs to be configured to the interface. +.Dq a valid 6to4 address +is an address which has the following properties. For ordinary nodes +in 6to4 site, you do not need +.Nm +interface; it is necessary only for site border router +(called +.Dq 6to4 router +in the specification). +.Pp If any of the following properties are not satisfied, .Nm raises runtime error on packet transmission. @@ -110,6 +117,78 @@ you may want to configure IPv6 prefix length as .Nm interface will check the IPv4 source address on packets, if the IPv6 prefix length is larger than 16. +.Sh RFC5569 (a.k.a. 6rd) +The +.Nm +interface works in the 6rd mode when one or more IPv6 addresses that +consists of an IPv6 prefix and 32-bit IPv4 part with a prefix length +equal to or shorter than 64. In 6rd protocol, an IPv6 address +.Li 2001:db8:c000:205::1/32 +means the following, for example: +.Bl -bullet +.It +The 6rd relay prefix is +.Li 2001:db8::/32 . +.It +The 6rd router's IPv4 address is +.Li 192.0.2.5 . +.El +.Pp +As you can see the IPv4 address is embedded in the IPv6 address just +after the prefix. While you can choose an IPv6 prefix length other +than 32, it must be from 0 to 32. +.Pp +Assuming this address is configured on the +.Nm +interface, it does the following: +.Bl -bullet +.It +An incoming IPv6 packet on +.Nm +will be encapsuled in an IPv4 packet with the source address +.Li 192.0.2.5 +and then the IPv4 packet is delivered based on the IPv4 routing table. +The IPv4 destination address is calculated from the destination +address of the original IPv6 packet in the same way as the source. +.It +An incoming IPv4 packet which encapsules an IPv6 packet whose +destination address matches a 6rd prefix with embedded IPv4 address +configured on the +.Nm +interface, the IPv6 packet will be decapsulated and delivered based on +the IPv6 routing table. Note that +.Nm +interface normally has a route which covers whole range of a 6rd relay +prefix, the delivered IPv6 packet can return to +.Nm +if there is no more specific route. In that case, the returned packet +will be discarded silently. +.El +.\" XXX: example configuration will be added +.\" .Pp +.\" By using this interface, you can configure a 6rd domain. For simplicity, +.\" we assume the following here: +.\" .Bl -bullet +.\" .It +.\" A 6rd Customer, who has an IPv6/IPv4 LAN and an IPv4-only access +.\" toward network of his Internet Service Provider. The Customer has +.\" a router called +.\" .Dq CE Pq Customer Edge +.\" Router, which can communicate between his LAN and the ISP over IPv4 +.\" and encapsulate +.\" his networks. +.\" .It +.\" A 6rd Provider, who provides IPv6 Internet reachability by using 6rd +.\" protocol. The Provider offers access to a router called +.\" .Dq PE Pq Provider Edge +.\" Router, which can communicate with +.\" .El +.\" .Pp +.\" A 6rd customer +.\" needs to configure +.\" .Nm +.\" on his CE (Customer Edge) router. +.Sh Other Functionality of the Interface .Pp .Nm can be configured to be ECN friendly. @@ -147,9 +226,6 @@ Packets with IPv4 multicast address as outer IPv4 source/destination Packets with limited broadcast address as outer IPv4 source/destination .Pq Li 255.0.0.0/8 .It -Packets with private address as outer IPv4 source/destination -.Pq Li 10.0.0.0/8 , 172.16.0.0/12 , 192.168.0.0/16 -.It Packets with subnet broadcast address as outer IPv4 source/destination. The check is made against subnet broadcast addresses for all of the directly connected subnets. @@ -164,6 +240,11 @@ The same set of rules are applied against the IPv4 address embedded into inner IPv6 address, if the IPv6 address matches 6to4 prefix. .El .Pp +In addition to them, packets with private address as outer IPv4 +source/destination +.Pq Li 10.0.0.0/8 , 172.16.0.0/12 , 192.168.0.0/16 +are filtered out only in the 6to4 mode. +.Pp It is recommended to filter/audit incoming IPv4 packet with IP protocol number 41, as necessary. It is also recommended to filter/audit encapsulated IPv6 packets as well. diff --git a/sys/dev/iicbus/ad7417.c b/sys/dev/iicbus/ad7417.c index 6ae16be..084b9f5 100644 --- a/sys/dev/iicbus/ad7417.c +++ b/sys/dev/iicbus/ad7417.c @@ -51,6 +51,8 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/ofw_bus.h> #include <powerpc/powermac/powermac_thermal.h> +#define FCU_ZERO_C_TO_K 2732 + /* CPU A/B sensors, temp and adc: AD7417. */ #define AD7417_TEMP 0x00 @@ -71,16 +73,6 @@ struct ad7417_sensor { } type; }; -struct write_data { - uint8_t reg; - uint8_t val; -}; - -struct read_data { - uint8_t reg; - uint16_t val; -}; - /* Regular bus attachment functions */ static int ad7417_probe(device_t); static int ad7417_attach(device_t); @@ -93,8 +85,6 @@ static int ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data); static int ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data); -static int ad7417_write_read(device_t dev, uint32_t addr, - struct write_data out, struct read_data *in); static int ad7417_diode_read(struct ad7417_sensor *sens); static int ad7417_adc_read(struct ad7417_sensor *sens); static int ad7417_sensor_read(struct ad7417_sensor *sens); @@ -128,8 +118,6 @@ static int ad7417_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff, int len) { unsigned char buf[4]; - int try = 0; - struct iic_msg msg[] = { { addr, IIC_M_WR, 0, buf } }; @@ -138,134 +126,76 @@ ad7417_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff, int len) buf[0] = reg; memcpy(buf + 1, buff, len); - for (;;) - { - if (iicbus_transfer(dev, msg, 1) == 0) - return (0); - - if (++try > 5) { - device_printf(dev, "iicbus write failed\n"); - return (-1); - } - pause("ad7417_write", hz); + if (iicbus_transfer(dev, msg, 1) != 0) { + device_printf(dev, "iicbus write failed\n"); + return (EIO); } + + return (0); + } static int ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data) { uint8_t buf[4]; - int err, try = 0; struct iic_msg msg[2] = { { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, { addr, IIC_M_RD, 1, buf }, }; - for (;;) - { - err = iicbus_transfer(dev, msg, 2); - if (err != 0) - goto retry; - - *data = *((uint8_t*)buf); - return (0); - retry: - if (++try > 5) { - device_printf(dev, "iicbus read failed\n"); - return (-1); - } - pause("ad7417_read_1", hz); + if (iicbus_transfer(dev, msg, 2) != 0) { + device_printf(dev, "iicbus read failed\n"); + return (EIO); } + + *data = *((uint8_t*)buf); + + return (0); } static int ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data) { uint8_t buf[4]; - int err, try = 0; struct iic_msg msg[2] = { { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, { addr, IIC_M_RD, 2, buf }, }; - for (;;) - { - err = iicbus_transfer(dev, msg, 2); - if (err != 0) - goto retry; - - *data = *((uint16_t*)buf); - return (0); - retry: - if (++try > 5) { - device_printf(dev, "iicbus read failed\n"); - return (-1); - } - pause("ad7417_read_2", hz); + if (iicbus_transfer(dev, msg, 2) != 0) { + device_printf(dev, "iicbus read failed\n"); + return (EIO); } -} -static int -ad7417_write_read(device_t dev, uint32_t addr, struct write_data out, - struct read_data *in) -{ - uint8_t buf[4]; - int err, try = 0; - - /* Do a combined write/read. */ - struct iic_msg msg[3] = { - { addr, IIC_M_WR, 2, buf }, - { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &in->reg }, - { addr, IIC_M_RD, 2, buf }, - }; + *data = *((uint16_t*)buf); - /* Prepare the write msg. */ - buf[0] = out.reg; - buf[1] = out.val & 0xff; - - for (;;) - { - err = iicbus_transfer(dev, msg, 3); - if (err != 0) - goto retry; - - in->val = *((uint16_t*)buf); - return (0); - retry: - if (++try > 5) { - device_printf(dev, "iicbus write/read failed\n"); - return (-1); - } - pause("ad7417_write_read", hz); - } + return (0); } static int ad7417_init_adc(device_t dev, uint32_t addr) { uint8_t buf; - int err; adc741x_config = 0; /* Clear Config2 */ buf = 0; - - err = ad7417_write(dev, addr, AD7417_CONFIG2, &buf, 1); + ad7417_write(dev, addr, AD7417_CONFIG2, &buf, 1); /* Read & cache Config1 */ buf = 0; - err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); - err = ad7417_read_1(dev, addr, AD7417_CONFIG, &buf); + ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); + + ad7417_read_1(dev, addr, AD7417_CONFIG, &buf); adc741x_config = (uint8_t)buf; /* Disable shutdown mode */ adc741x_config &= 0xfe; buf = adc741x_config; - err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); - if (err < 0) - return (-1); + ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); return (0); @@ -370,8 +300,8 @@ ad7417_fill_sensor_prop(device_t dev) continue; /* Make up some ranges */ - sc->sc_sensors[j].therm.target_temp = 500 + ZERO_C_TO_K; - sc->sc_sensors[j].therm.max_temp = 900 + ZERO_C_TO_K; + sc->sc_sensors[j].therm.target_temp = 500 + 2732; + sc->sc_sensors[j].therm.max_temp = 900 + 2732; pmac_thermal_sensor_register(&sc->sc_sensors[j].therm); } @@ -461,13 +391,8 @@ ad7417_get_temp(device_t dev, uint32_t addr, int *temp) { uint16_t buf[2]; uint16_t read; - int err; - - err = ad7417_read_2(dev, addr, AD7417_TEMP, buf); - - if (err < 0) - return (-1); + ad7417_read_2(dev, addr, AD7417_TEMP, buf); read = *((int16_t*)buf); /* The ADC is 10 bit, the resolution is 0.25 C. @@ -481,25 +406,22 @@ static int ad7417_get_adc(device_t dev, uint32_t addr, unsigned int *value, uint8_t chan) { - uint8_t tmp; - int err; - struct write_data config; - struct read_data data; + uint8_t cfg1, tmp; + uint16_t read, buf[2]; + + ad7417_read_1(dev, addr, AD7417_CONFIG, &cfg1); tmp = chan << 5; - config.reg = AD7417_CONFIG; - data.reg = AD7417_ADC; - data.val = 0; - err = ad7417_read_1(dev, addr, AD7417_CONFIG, &config.val); + cfg1 = (cfg1 & ~AD7417_CONFMASK) | (tmp & AD7417_CONFMASK); - config.val = (config.val & ~AD7417_CONFMASK) | (tmp & AD7417_CONFMASK); + ad7417_write(dev, addr, AD7417_CONFIG, &cfg1, 1); - err = ad7417_write_read(dev, addr, config, &data); - if (err < 0) - return (-1); + ad7417_read_2(dev, addr, AD7417_ADC, buf); - *value = ((uint32_t)data.val) >> 6; + read = *((uint16_t*)buf); + + *value = ((uint32_t)read) >> 6; return (0); } @@ -522,9 +444,6 @@ ad7417_diode_read(struct ad7417_sensor *sens) } rawval = ad7417_adc_read(sens); - if (rawval < 0) - return (-1); - if (strstr(sens->therm.name, "CPU B") != NULL) { diode_slope = eeprom[1][0x11] >> 16; diode_offset = (int16_t)(eeprom[1][0x11] & 0xffff) << 12; @@ -536,7 +455,7 @@ ad7417_diode_read(struct ad7417_sensor *sens) temp = (rawval*diode_slope + diode_offset) >> 2; temp = (10*(temp >> 16)) + ((10*(temp & 0xffff)) >> 16); - return (temp + ZERO_C_TO_K); + return (temp + FCU_ZERO_C_TO_K); } static int @@ -569,8 +488,7 @@ ad7417_adc_read(struct ad7417_sensor *sens) chan = 1; } - if (ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan) < 0) - return (-1); + ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan); return (temp); } @@ -585,13 +503,11 @@ ad7417_sensor_read(struct ad7417_sensor *sens) sc = device_get_softc(sens->dev); /* Init the ADC. */ - if (ad7417_init_adc(sc->sc_dev, sc->sc_addr) < 0) - return (-1); + ad7417_init_adc(sc->sc_dev, sc->sc_addr); if (sens->type == ADC7417_TEMP_SENSOR) { - if (ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp) < 0) - return (-1); - temp += ZERO_C_TO_K; + ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp); + temp += FCU_ZERO_C_TO_K; } else { temp = ad7417_adc_read(sens); } diff --git a/sys/net/if_stf.c b/sys/net/if_stf.c index 1ef5581..7d136fd 100644 --- a/sys/net/if_stf.c +++ b/sys/net/if_stf.c @@ -3,6 +3,7 @@ /*- * Copyright (C) 2000 WIDE Project. + * Copyright (c) 2010-2011 Hiroki Sato <hrs@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,7 +32,7 @@ */ /* - * 6to4 interface, based on RFC3056. + * 6to4 interface, based on RFC 3056 + 6rd (RFC 5969) support. * * 6to4 interface is NOT capable of link-layer (I mean, IPv4) multicasting. * There is no address mapping defined from IPv6 multicast address to IPv4 @@ -60,7 +61,7 @@ * ICMPv6: * - Redirects cannot be used due to the lack of link-local address. * - * stf interface does not have, and will not need, a link-local address. + * stf interface does not have, and will not need, a link-local address. * It seems to have no real benefit and does not help the above symptoms much. * Even if we assign link-locals to interface, we cannot really * use link-local unicast/multicast on top of 6to4 cloud (since there's no @@ -72,6 +73,11 @@ * http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt * for details. The code tries to filter out some of malicious packets. * Note that there is no way to be 100% secure. + * + * 6rd (RFC 5969) extension is enabled when an IPv6 GUA other than + * 2002::/16 is assigned. The stf(4) calculates a 6rd delegated + * prefix from a 6rd prefix and an IPv4 address. + * */ #include "opt_inet.h" @@ -120,15 +126,41 @@ #include <security/mac/mac_framework.h> +#define STF_DEBUG 1 +#define ip_sprintf(buf, a) \ + sprintf(buf, "%d.%d.%d.%d", \ + (ntohl((a)->s_addr)>>24)&0xFF, \ + (ntohl((a)->s_addr)>>16)&0xFF, \ + (ntohl((a)->s_addr)>>8)&0xFF, \ + (ntohl((a)->s_addr))&0xFF); +#if STF_DEBUG +#define DEBUG_PRINTF(a, ...) \ + do { \ + if (V_stf_debug >= a) \ + printf(__VA_ARGS__); \ + } while (0) +#else +#define DEBUG_PRINTF(a, ...) +#endif + SYSCTL_DECL(_net_link); SYSCTL_NODE(_net_link, IFT_STF, stf, CTLFLAG_RW, 0, "6to4 Interface"); -static int stf_route_cache = 1; -SYSCTL_INT(_net_link_stf, OID_AUTO, route_cache, CTLFLAG_RW, - &stf_route_cache, 0, "Caching of IPv4 routes for 6to4 Output"); +static VNET_DEFINE(int, stf_route_cache) = 1; +#define V_stf_route_cache VNET(stf_route_cache) +SYSCTL_VNET_INT(_net_link_stf, OID_AUTO, route_cache, CTLFLAG_RW, + &VNET_NAME(stf_route_cache), 0, + "Enable caching of IPv4 routes for 6to4 output."); + +#if STF_DEBUG +static VNET_DEFINE(int, stf_debug) = 0; +#define V_stf_debug VNET(stf_debug) +SYSCTL_VNET_INT(_net_link_stf, OID_AUTO, stf_debug, CTLFLAG_RW, + &VNET_NAME(stf_debug), 0, + "Enable displaying verbose debug message of stf interfaces"); +#endif #define STFNAME "stf" -#define STFUNIT 0 #define IN6_IS_ADDR_6TO4(x) (ntohs((x)->s6_addr16[0]) == 0x2002) @@ -145,17 +177,27 @@ struct stf_softc { struct route_in6 __sc_ro6; /* just for safety */ } __sc_ro46; #define sc_ro __sc_ro46.__sc_ro4 - struct mtx sc_ro_mtx; + struct mtx sc_mtx; u_int sc_fibnum; const struct encaptab *encap_cookie; + u_int sc_flags; + eventhandler_tag sc_ifaddr_event_tag; + LIST_ENTRY(stf_softc) stf_list; }; #define STF2IFP(sc) ((sc)->sc_ifp) -/* - * Note that mutable fields in the softc are not currently locked. - * We do lock sc_ro in stf_output though. - */ +static struct mtx stf_mtx; static MALLOC_DEFINE(M_STF, STFNAME, "6to4 Tunnel Interface"); +static VNET_DEFINE(LIST_HEAD(, stf_softc), stf_softc_list); +#define V_stf_softc_list VNET(stf_softc_list) + +#define STF_LOCK_INIT(sc) mtx_init(&(sc)->sc_mtx, "stf softc", \ + NULL, MTX_DEF); +#define STF_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx) +#define STF_LOCK(sc) mtx_lock(&(sc)->sc_mtx) +#define STF_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) +#define STF_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) + static const int ip_stf_ttl = 40; extern struct domain inetdomain; @@ -170,8 +212,6 @@ struct protosw in_stf_protosw = { .pr_usrreqs = &rip_usrreqs }; -static char *stfnames[] = {"stf0", "stf", "6to4", NULL}; - static int stfmodevent(module_t, int, void *); static int stf_encapcheck(const struct mbuf *, int, int, void *); static struct in6_ifaddr *stf_getsrcifa6(struct ifnet *); @@ -184,68 +224,47 @@ static int stf_checkaddr6(struct stf_softc *, struct in6_addr *, struct ifnet *); static void stf_rtrequest(int, struct rtentry *, struct rt_addrinfo *); static int stf_ioctl(struct ifnet *, u_long, caddr_t); +static int stf_is_up(struct ifnet *); -static int stf_clone_match(struct if_clone *, const char *); -static int stf_clone_create(struct if_clone *, char *, size_t, caddr_t); -static int stf_clone_destroy(struct if_clone *, struct ifnet *); -struct if_clone stf_cloner = IFC_CLONE_INITIALIZER(STFNAME, NULL, 0, - NULL, stf_clone_match, stf_clone_create, stf_clone_destroy); +#define STF_GETIN4_USE_CACHE 1 +static struct sockaddr_in *stf_getin4addr(struct sockaddr_in *, + struct ifaddr *, + int); +static struct sockaddr_in *stf_getin4addr_in6(struct sockaddr_in *, + struct ifaddr *, + struct in6_addr *); +static struct sockaddr_in *stf_getin4addr_sin6(struct sockaddr_in *, + struct ifaddr *, + struct sockaddr_in6 *); +static void stf_ifaddr_change(void *, struct ifnet *); -static int -stf_clone_match(struct if_clone *ifc, const char *name) -{ - int i; +static int stf_clone_create(struct if_clone *, int, caddr_t); +static void stf_clone_destroy(struct ifnet *); - for(i = 0; stfnames[i] != NULL; i++) { - if (strcmp(stfnames[i], name) == 0) - return (1); - } - - return (0); -} +IFC_SIMPLE_DECLARE(stf, 0); static int -stf_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) +stf_clone_create(struct if_clone *ifc, int unit, caddr_t params) { - int err, unit; struct stf_softc *sc; struct ifnet *ifp; - /* - * We can only have one unit, but since unit allocation is - * already locked, we use it to keep from allocating extra - * interfaces. - */ - unit = STFUNIT; - err = ifc_alloc_unit(ifc, &unit); - if (err != 0) - return (err); - sc = malloc(sizeof(struct stf_softc), M_STF, M_WAITOK | M_ZERO); + sc->sc_fibnum = curthread->td_proc->p_fibnum; ifp = STF2IFP(sc) = if_alloc(IFT_STF); - if (ifp == NULL) { + if (sc->sc_ifp == NULL) { free(sc, M_STF); - ifc_free_unit(ifc, unit); - return (ENOSPC); + return (ENOMEM); } + STF_LOCK_INIT(sc); ifp->if_softc = sc; - sc->sc_fibnum = curthread->td_proc->p_fibnum; + if_initname(ifp, ifc->ifc_name, unit); - /* - * Set the name manually rather then using if_initname because - * we don't conform to the default naming convention for interfaces. - */ - strlcpy(ifp->if_xname, name, IFNAMSIZ); - ifp->if_dname = ifc->ifc_name; - ifp->if_dunit = IF_DUNIT_NONE; - - mtx_init(&(sc)->sc_ro_mtx, "stf ro", NULL, MTX_DEF); sc->encap_cookie = encap_attach_func(AF_INET, IPPROTO_IPV6, stf_encapcheck, &in_stf_protosw, sc); if (sc->encap_cookie == NULL) { if_printf(ifp, "attach failed\n"); free(sc, M_STF); - ifc_free_unit(ifc, unit); return (ENOMEM); } @@ -255,41 +274,63 @@ stf_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) ifp->if_snd.ifq_maxlen = ifqmaxlen; if_attach(ifp); bpfattach(ifp, DLT_NULL, sizeof(u_int32_t)); + + mtx_lock(&stf_mtx); + LIST_INSERT_HEAD(&V_stf_softc_list, sc, stf_list); + mtx_unlock(&stf_mtx); + + sc->sc_ifaddr_event_tag = + EVENTHANDLER_REGISTER(ifaddr_event, stf_ifaddr_change, NULL, + EVENTHANDLER_PRI_ANY); + return (0); } -static int -stf_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) +static void +stf_clone_destroy(struct ifnet *ifp) { struct stf_softc *sc = ifp->if_softc; int err; + mtx_lock(&stf_mtx); + LIST_REMOVE(sc, stf_list); + mtx_unlock(&stf_mtx); + + EVENTHANDLER_DEREGISTER(ifaddr_event, sc->sc_ifaddr_event_tag); + err = encap_detach(sc->encap_cookie); KASSERT(err == 0, ("Unexpected error detaching encap_cookie")); - mtx_destroy(&(sc)->sc_ro_mtx); bpfdetach(ifp); if_detach(ifp); if_free(ifp); + STF_LOCK_DESTROY(sc); free(sc, M_STF); - ifc_free_unit(ifc, STFUNIT); - return (0); + return; } +static void +vnet_stf_init(const void *unused __unused) +{ + + LIST_INIT(&V_stf_softc_list); +} +VNET_SYSINIT(vnet_stf_init, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, vnet_stf_init, + NULL); + static int -stfmodevent(mod, type, data) - module_t mod; - int type; - void *data; +stfmodevent(module_t mod, int type, void *data) { switch (type) { case MOD_LOAD: + mtx_init(&stf_mtx, "stf_mtx", NULL, MTX_DEF); if_clone_attach(&stf_cloner); break; case MOD_UNLOAD: if_clone_detach(&stf_cloner); + mtx_destroy(&stf_mtx); break; default: return (EOPNOTSUPP); @@ -305,28 +346,31 @@ static moduledata_t stf_mod = { }; DECLARE_MODULE(if_stf, stf_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); +MODULE_VERSION(if_stf, 1); static int -stf_encapcheck(m, off, proto, arg) - const struct mbuf *m; - int off; - int proto; - void *arg; +stf_encapcheck(const struct mbuf *m, int off, int proto, void *arg) { struct ip ip; struct in6_ifaddr *ia6; + struct sockaddr_in ia6_in4addr; + struct sockaddr_in ia6_in4mask; + struct sockaddr_in *sin; struct stf_softc *sc; - struct in_addr a, b, mask; + struct ifnet *ifp; + int ret = 0; + DEBUG_PRINTF(1, "%s: enter\n", __func__); sc = (struct stf_softc *)arg; if (sc == NULL) return 0; + ifp = STF2IFP(sc); - if ((STF2IFP(sc)->if_flags & IFF_UP) == 0) + if ((ifp->if_flags & IFF_UP) == 0) return 0; /* IFF_LINK0 means "no decapsulation" */ - if ((STF2IFP(sc)->if_flags & IFF_LINK0) != 0) + if ((ifp->if_flags & IFF_LINK0) != 0) return 0; if (proto != IPPROTO_IPV6) @@ -338,86 +382,162 @@ stf_encapcheck(m, off, proto, arg) if (ip.ip_v != 4) return 0; - ia6 = stf_getsrcifa6(STF2IFP(sc)); + /* Lookup an ia6 whose IPv4 addr encoded in the IPv6 addr is valid. */ + ia6 = stf_getsrcifa6(ifp); if (ia6 == NULL) return 0; + sin = stf_getin4addr(&ia6_in4addr, &ia6->ia_ifa, STF_GETIN4_USE_CACHE); + if (sin == NULL) + return 0; +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + + ip6_sprintf(buf, &satosin6(ia6->ia_ifa.ifa_addr)->sin6_addr); + DEBUG_PRINTF(1, "%s: ia6->ia_ifa.ifa_addr = %s\n", __func__, buf); + ip6_sprintf(buf, &ia6->ia_addr.sin6_addr); + DEBUG_PRINTF(1, "%s: ia6->ia_addr = %s\n", __func__, buf); + ip6_sprintf(buf, &satosin6(ia6->ia_ifa.ifa_netmask)->sin6_addr); + DEBUG_PRINTF(1, "%s: ia6->ia_ifa.ifa_netmask = %s\n", __func__, buf); + ip6_sprintf(buf, &ia6->ia_prefixmask.sin6_addr); + DEBUG_PRINTF(1, "%s: ia6->ia_prefixmask = %s\n", __func__, buf); + + ip_sprintf(buf, &ia6_in4addr.sin_addr); + DEBUG_PRINTF(1, "%s: ia6_in4addr.sin_addr = %s\n", __func__, buf); + ip_sprintf(buf, &ip.ip_src); + DEBUG_PRINTF(1, "%s: ip.ip_src = %s\n", __func__, buf); + ip_sprintf(buf, &ip.ip_dst); + DEBUG_PRINTF(1, "%s: ip.ip_dst = %s\n", __func__, buf); + } +#endif /* * check if IPv4 dst matches the IPv4 address derived from the * local 6to4 address. * success on: dst = 10.1.1.1, ia6->ia_addr = 2002:0a01:0101:... */ - if (bcmp(GET_V4(&ia6->ia_addr.sin6_addr), &ip.ip_dst, - sizeof(ip.ip_dst)) != 0) { - ifa_free(&ia6->ia_ifa); - return 0; + DEBUG_PRINTF(1, "%s: check1: ia6_in4addr.sin_addr == ip.ip_dst?\n", __func__); + if (ia6_in4addr.sin_addr.s_addr != ip.ip_dst.s_addr) { + DEBUG_PRINTF(1, "%s: check1: false. Ignore this packet.\n", __func__); + goto freeit; } - /* - * check if IPv4 src matches the IPv4 address derived from the - * local 6to4 address masked by prefixmask. - * success on: src = 10.1.1.1, ia6->ia_addr = 2002:0a00:.../24 - * fail on: src = 10.1.1.1, ia6->ia_addr = 2002:0b00:.../24 - */ - bzero(&a, sizeof(a)); - bcopy(GET_V4(&ia6->ia_addr.sin6_addr), &a, sizeof(a)); - bcopy(GET_V4(&ia6->ia_prefixmask.sin6_addr), &mask, sizeof(mask)); - ifa_free(&ia6->ia_ifa); - a.s_addr &= mask.s_addr; - b = ip.ip_src; - b.s_addr &= mask.s_addr; - if (a.s_addr != b.s_addr) - return 0; + DEBUG_PRINTF(1, "%s: check2: ia6->ia_addr is 2002::/16?\n", __func__); + if (IN6_IS_ADDR_6TO4(&ia6->ia_addr.sin6_addr)) { + /* 6to4 (RFC 3056) */ + /* + * check if IPv4 src matches the IPv4 address derived + * from the local 6to4 address masked by prefixmask. + * success on: src = 10.1.1.1, ia6->ia_addr = 2002:0a00:.../24 + * fail on: src = 10.1.1.1, ia6->ia_addr = 2002:0b00:.../24 + */ + DEBUG_PRINTF(1, "%s: check2: true.\n", __func__); + + memcpy(&ia6_in4mask.sin_addr, + GET_V4(&ia6->ia_prefixmask.sin6_addr), + sizeof(ia6_in4mask)); +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + + ip_sprintf(buf, &ia6_in4addr.sin_addr); + DEBUG_PRINTF(1, "%s: ia6->ia_addr = %s\n", + __func__, buf); + ip_sprintf(buf, &ip.ip_src); + DEBUG_PRINTF(1, "%s: ip.ip_src = %s\n", + __func__, buf); + ip_sprintf(buf, &ia6_in4mask.sin_addr); + DEBUG_PRINTF(1, "%s: ia6->ia_prefixmask = %s\n", + __func__, buf); + + DEBUG_PRINTF(1, "%s: check3: ia6_in4addr.sin_addr & mask == ip.ip_src & mask\n", + __func__); + } +#endif + if ((ia6_in4addr.sin_addr.s_addr & ia6_in4mask.sin_addr.s_addr) != + (ip.ip_src.s_addr & ia6_in4mask.sin_addr.s_addr)) { + DEBUG_PRINTF(1, "%s: check3: false. Ignore this packet.\n", + __func__); + goto freeit; + } + } else { + /* 6rd (RFC 5569) */ + DEBUG_PRINTF(1, "%s: check2: false. 6rd.\n", __func__); + /* + * No restriction on the src address in the case of + * 6rd because the stf(4) interface always has a + * prefix which covers whole of IPv4 src address + * range. So, stf_output() will catch all of + * 6rd-capsuled IPv4 traffic with suspicious inner dst + * IPv4 address (i.e. the IPv6 destination address is + * one the admin does not like to route to outside), + * and then it discard them silently. + */ + } + DEBUG_PRINTF(1, "%s: all clear!\n", __func__); /* stf interface makes single side match only */ - return 32; + ret = 32; +freeit: + ifa_free(&ia6->ia_ifa); + + return (ret); } static struct in6_ifaddr * -stf_getsrcifa6(ifp) - struct ifnet *ifp; +stf_getsrcifa6(struct ifnet *ifp) { - struct ifaddr *ia; + struct ifaddr *ifa; struct in_ifaddr *ia4; - struct sockaddr_in6 *sin6; - struct in_addr in; + struct sockaddr_in *sin; + struct sockaddr_in in4; if_addr_rlock(ifp); - TAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) { - if (ia->ifa_addr->sa_family != AF_INET6) + TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr->sa_family != AF_INET6) continue; - sin6 = (struct sockaddr_in6 *)ia->ifa_addr; - if (!IN6_IS_ADDR_6TO4(&sin6->sin6_addr)) + if ((sin = stf_getin4addr(&in4, ifa, + STF_GETIN4_USE_CACHE)) == NULL) continue; - - bcopy(GET_V4(&sin6->sin6_addr), &in, sizeof(in)); - LIST_FOREACH(ia4, INADDR_HASH(in.s_addr), ia_hash) - if (ia4->ia_addr.sin_addr.s_addr == in.s_addr) + LIST_FOREACH(ia4, INADDR_HASH(sin->sin_addr.s_addr), ia_hash) + if (ia4->ia_addr.sin_addr.s_addr == sin->sin_addr.s_addr) break; if (ia4 == NULL) continue; - ifa_ref(ia); +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + + ip6_sprintf(buf, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr); + DEBUG_PRINTF(1, "%s: ifa->ifa_addr->sin6_addr = %s\n", + __func__, buf); + ip_sprintf(buf, &ia4->ia_addr.sin_addr); + DEBUG_PRINTF(1, "%s: ia4->ia_addr.sin_addr = %s\n", + __func__, buf); + } +#endif + ifa_ref(ifa); if_addr_runlock(ifp); - return (struct in6_ifaddr *)ia; + return (ifatoia6(ifa)); } if_addr_runlock(ifp); + return NULL; } static int -stf_output(ifp, m, dst, ro) - struct ifnet *ifp; - struct mbuf *m; - struct sockaddr *dst; - struct route *ro; +stf_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct route *ro) { struct stf_softc *sc; struct sockaddr_in6 *dst6; struct route *cached_route; - struct in_addr in4; - caddr_t ptr; + struct sockaddr_in *sin; + struct sockaddr_in in4; struct sockaddr_in *dst4; u_int8_t tos; struct ip *ip; @@ -479,20 +599,28 @@ stf_output(ifp, m, dst, ro) /* * Pickup the right outer dst addr from the list of candidates. * ip6_dst has priority as it may be able to give us shorter IPv4 hops. + * ip6_dst: destination addr in the packet header. + * dst6: destination addr specified in function argument. */ - ptr = NULL; - if (IN6_IS_ADDR_6TO4(&ip6->ip6_dst)) - ptr = GET_V4(&ip6->ip6_dst); - else if (IN6_IS_ADDR_6TO4(&dst6->sin6_addr)) - ptr = GET_V4(&dst6->sin6_addr); - else { + DEBUG_PRINTF(1, "%s: dst addr selection\n", __func__); + sin = stf_getin4addr_in6(&in4, &ia6->ia_ifa, &ip6->ip6_dst); + if (sin == NULL) + sin = stf_getin4addr_in6(&in4, &ia6->ia_ifa, &dst6->sin6_addr); + if (sin == NULL) { ifa_free(&ia6->ia_ifa); m_freem(m); ifp->if_oerrors++; return ENETUNREACH; } - bcopy(ptr, &in4, sizeof(in4)); +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + ip_sprintf(buf, &sin->sin_addr); + DEBUG_PRINTF(1, "%s: ip_dst = %s\n", __func__, buf); + } +#endif if (bpf_peers_present(ifp->if_bpf)) { /* * We need to prepend the address family as @@ -516,11 +644,26 @@ stf_output(ifp, m, dst, ro) ip = mtod(m, struct ip *); bzero(ip, sizeof(*ip)); + bcopy(&in4.sin_addr, &ip->ip_dst, sizeof(ip->ip_dst)); + + sin = stf_getin4addr_sin6(&in4, &ia6->ia_ifa, &ia6->ia_addr); + if (sin == NULL) { + ifa_free(&ia6->ia_ifa); + m_freem(m); + ifp->if_oerrors++; + return ENETUNREACH; + } + bcopy(&in4.sin_addr, &ip->ip_src, sizeof(ip->ip_src)); +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); - bcopy(GET_V4(&((struct sockaddr_in6 *)&ia6->ia_addr)->sin6_addr), - &ip->ip_src, sizeof(ip->ip_src)); + ip_sprintf(buf, &ip->ip_src); + DEBUG_PRINTF(1, "%s: ip_src = %s\n", __func__, buf); + } +#endif ifa_free(&ia6->ia_ifa); - bcopy(&in4, &ip->ip_dst, sizeof(ip->ip_dst)); ip->ip_p = IPPROTO_IPV6; ip->ip_ttl = ip_stf_ttl; ip->ip_len = m->m_pkthdr.len; /*host order*/ @@ -529,7 +672,7 @@ stf_output(ifp, m, dst, ro) else ip_ecn_ingress(ECN_NOCARE, &ip->ip_tos, &tos); - if (!stf_route_cache) { + if (!V_stf_route_cache) { cached_route = NULL; goto sendit; } @@ -537,7 +680,7 @@ stf_output(ifp, m, dst, ro) /* * Do we have a cached route? */ - mtx_lock(&(sc)->sc_ro_mtx); + STF_LOCK(sc); dst4 = (struct sockaddr_in *)&sc->sc_ro.ro_dst; if (dst4->sin_family != AF_INET || bcmp(&dst4->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst)) != 0) { @@ -555,8 +698,15 @@ stf_output(ifp, m, dst, ro) rtalloc_fib(&sc->sc_ro, sc->sc_fibnum); if (sc->sc_ro.ro_rt == NULL) { m_freem(m); - mtx_unlock(&(sc)->sc_ro_mtx); ifp->if_oerrors++; + STF_UNLOCK(sc); + return ENETUNREACH; + } + if (sc->sc_ro.ro_rt->rt_ifp == ifp) { + /* infinite loop detection */ + m_free(m); + ifp->if_oerrors++; + STF_UNLOCK(sc); return ENETUNREACH; } } @@ -565,34 +715,31 @@ stf_output(ifp, m, dst, ro) sendit: M_SETFIB(m, sc->sc_fibnum); ifp->if_opackets++; + DEBUG_PRINTF(1, "%s: ip_output dispatch.\n", __func__); error = ip_output(m, NULL, cached_route, 0, NULL, NULL); if (cached_route != NULL) - mtx_unlock(&(sc)->sc_ro_mtx); + STF_UNLOCK(sc); return error; } static int -isrfc1918addr(in) - struct in_addr *in; +isrfc1918addr(struct in_addr *in) { /* * returns 1 if private address range: * 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 */ - if ((ntohl(in->s_addr) & 0xff000000) >> 24 == 10 || - (ntohl(in->s_addr) & 0xfff00000) >> 16 == 172 * 256 + 16 || - (ntohl(in->s_addr) & 0xffff0000) >> 16 == 192 * 256 + 168) + if ((ntohl(in->s_addr) & 0xff000000) == 10 << 24 || + (ntohl(in->s_addr) & 0xfff00000) == (172 * 256 + 16) << 16 || + (ntohl(in->s_addr) & 0xffff0000) == (192 * 256 + 168) << 16 ) return 1; return 0; } static int -stf_checkaddr4(sc, in, inifp) - struct stf_softc *sc; - struct in_addr *in; - struct ifnet *inifp; /* incoming interface */ +stf_checkaddr4(struct stf_softc *sc, struct in_addr *in, struct ifnet *inifp) { struct in_ifaddr *ia4; @@ -608,20 +755,10 @@ stf_checkaddr4(sc, in, inifp) } /* - * reject packets with private address range. - * (requirement from RFC3056 section 2 1st paragraph) - */ - if (isrfc1918addr(in)) - return -1; - - /* * reject packets with broadcast */ IN_IFADDR_RLOCK(); - for (ia4 = TAILQ_FIRST(&V_in_ifaddrhead); - ia4; - ia4 = TAILQ_NEXT(ia4, ia_link)) - { + TAILQ_FOREACH(ia4, &V_in_ifaddrhead, ia_link) { if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0) continue; if (in->s_addr == ia4->ia_broadaddr.sin_addr.s_addr) { @@ -640,7 +777,7 @@ stf_checkaddr4(sc, in, inifp) bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; - sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_len = sizeof(sin); sin.sin_addr = *in; rt = rtalloc1_fib((struct sockaddr *)&sin, 0, 0UL, sc->sc_fibnum); @@ -661,10 +798,7 @@ stf_checkaddr4(sc, in, inifp) } static int -stf_checkaddr6(sc, in6, inifp) - struct stf_softc *sc; - struct in6_addr *in6; - struct ifnet *inifp; /* incoming interface */ +stf_checkaddr6(struct stf_softc *sc, struct in6_addr *in6, struct ifnet *inifp) { /* * check 6to4 addresses @@ -688,9 +822,7 @@ stf_checkaddr6(sc, in6, inifp) } void -in_stf_input(m, off) - struct mbuf *m; - int off; +in_stf_input(struct mbuf *m, int off) { int proto; struct stf_softc *sc; @@ -698,6 +830,7 @@ in_stf_input(m, off) struct ip6_hdr *ip6; u_int8_t otos, itos; struct ifnet *ifp; + struct route_in6 rin6; proto = mtod(m, struct ip *)->ip_p; @@ -721,6 +854,17 @@ in_stf_input(m, off) mac_ifnet_create_mbuf(ifp, m); #endif +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + + ip_sprintf(buf, &ip->ip_dst); + DEBUG_PRINTF(1, "%s: ip->ip_dst = %s\n", __func__, buf); + ip_sprintf(buf, &ip->ip_src); + DEBUG_PRINTF(1, "%s: ip->ip_src = %s\n", __func__, buf); + } +#endif /* * perform sanity check against outer src/dst. * for source, perform ingress filter as well. @@ -741,6 +885,17 @@ in_stf_input(m, off) } ip6 = mtod(m, struct ip6_hdr *); +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + + ip6_sprintf(buf, &ip6->ip6_dst); + DEBUG_PRINTF(1, "%s: ip6->ip6_dst = %s\n", __func__, buf); + ip6_sprintf(buf, &ip6->ip6_src); + DEBUG_PRINTF(1, "%s: ip6->ip6_src = %s\n", __func__, buf); + } +#endif /* * perform sanity check against inner src/dst. * for source, perform ingress filter as well. @@ -751,6 +906,41 @@ in_stf_input(m, off) return; } + /* + * reject packets with private address range. + * (requirement from RFC3056 section 2 1st paragraph) + */ + if ((IN6_IS_ADDR_6TO4(&ip6->ip6_src) && isrfc1918addr(&ip->ip_src)) || + (IN6_IS_ADDR_6TO4(&ip6->ip6_dst) && isrfc1918addr(&ip->ip_dst))) { + m_freem(m); + return; + } + + /* + * Ignore if the destination is the same stf interface because + * all of valid IPv6 outgoing traffic should go interfaces + * except for it. + */ + memset(&rin6, 0, sizeof(rin6)); + rin6.ro_dst.sin6_len = sizeof(rin6.ro_dst); + rin6.ro_dst.sin6_family = AF_INET6; + memcpy(&rin6.ro_dst.sin6_addr, &ip6->ip6_dst, + sizeof(rin6.ro_dst.sin6_addr)); + rtalloc((struct route *)&rin6); + if (rin6.ro_rt == NULL) { + DEBUG_PRINTF(1, "%s: no IPv6 dst. Ignored.\n", __func__); + m_free(m); + return; + } + if ((rin6.ro_rt->rt_ifp == ifp) && + (!IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &rin6.ro_dst.sin6_addr))) { + DEBUG_PRINTF(1, "%s: IPv6 dst is the same stf. Ignored.\n", __func__); + RTFREE(rin6.ro_rt); + m_free(m); + return; + } + RTFREE(rin6.ro_rt); + itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; if ((ifp->if_flags & IFF_LINK1) != 0) ip_ecn_egress(ECN_ALLOWED, &otos, &itos); @@ -760,7 +950,7 @@ in_stf_input(m, off) ip6->ip6_flow |= htonl((u_int32_t)itos << 20); m->m_pkthdr.rcvif = ifp; - + if (bpf_peers_present(ifp->if_bpf)) { /* * We need to prepend the address family as @@ -773,6 +963,7 @@ in_stf_input(m, off) bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m); } + DEBUG_PRINTF(1, "%s: netisr_dispatch(NETISR_IPV6)\n", __func__); /* * Put the packet to the network layer input queue according to the * specified address family. @@ -786,50 +977,409 @@ in_stf_input(m, off) /* ARGSUSED */ static void -stf_rtrequest(cmd, rt, info) - int cmd; - struct rtentry *rt; - struct rt_addrinfo *info; +stf_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info) { + RT_LOCK_ASSERT(rt); rt->rt_rmx.rmx_mtu = IPV6_MMTU; } +/* Check whether we have at least one instance with IFF_UP. */ static int -stf_ioctl(ifp, cmd, data) - struct ifnet *ifp; - u_long cmd; - caddr_t data; +stf_is_up(struct ifnet *ifp) +{ + struct stf_softc *scp; + struct stf_softc *sc_cur; + struct stf_softc *sc_is_up; + + sc_is_up = NULL; + if ((sc_cur = ifp->if_softc) == NULL) + return (EINVAL); + + mtx_lock(&stf_mtx); + LIST_FOREACH(scp, &V_stf_softc_list, stf_list) { + if (scp == sc_cur) + continue; + if ((STF2IFP(scp)->if_flags & IFF_UP) != 0) { + sc_is_up = scp; + break; + } + } + mtx_unlock(&stf_mtx); + + /* We already has at least one instance with IFF_UP. */ + if (stf_is_up != NULL) + return (ENOSPC); + + return (0); +} + +static struct sockaddr_in * +stf_getin4addr_in6(struct sockaddr_in *sin, + struct ifaddr *ifa, + struct in6_addr *in6) +{ + struct sockaddr_in6 sin6; + + DEBUG_PRINTF(1, "%s: enter.\n", __func__); + if (ifa == NULL || in6 == NULL) + return NULL; + + memset(&sin6, 0, sizeof(sin6)); + memcpy(&sin6.sin6_addr, in6, sizeof(sin6.sin6_addr)); + sin6.sin6_len = sizeof(sin6); + sin6.sin6_family = AF_INET6; + + return(stf_getin4addr_sin6(sin, ifa, &sin6)); +} + +static struct sockaddr_in * +stf_getin4addr_sin6(struct sockaddr_in *sin, + struct ifaddr *ifa, + struct sockaddr_in6 *sin6) +{ + struct in6_ifaddr ia6; + int i; + + DEBUG_PRINTF(1, "%s: enter.\n", __func__); + if (ifa == NULL || sin6 == NULL) + return NULL; + + memset(&ia6, 0, sizeof(ia6)); + memcpy(&ia6, ifatoia6(ifa), sizeof(ia6)); + + /* + * Use prefixmask information from ifa, and + * address information from sin6. + */ + ia6.ia_addr.sin6_family = AF_INET6; + ia6.ia_ifa.ifa_addr = (struct sockaddr *)&ia6.ia_addr; + ia6.ia_ifa.ifa_dstaddr = NULL; + ia6.ia_ifa.ifa_netmask = (struct sockaddr *)&ia6.ia_prefixmask; + +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + + ip6_sprintf(buf, &sin6->sin6_addr); + DEBUG_PRINTF(1, "%s: sin6->sin6_addr = %s\n", __func__, buf); + ip6_sprintf(buf, &ia6.ia_addr.sin6_addr); + DEBUG_PRINTF(1, "%s: ia6.ia_addr.sin6_addr = %s\n", __func__, buf); + ip6_sprintf(buf, &ia6.ia_prefixmask.sin6_addr); + DEBUG_PRINTF(1, "%s: ia6.ia_prefixmask.sin6_addr = %s\n", __func__, buf); + } +#endif + + /* + * When (src addr & src mask) != (dst (sin6) addr & src mask), + * the dst is not in the 6rd domain. The IPv4 address must + * not be used. + */ + for (i = 0; i < sizeof(ia6.ia_addr.sin6_addr); i++) { + if ((((u_char *)&ia6.ia_addr.sin6_addr)[i] & + ((u_char *)&ia6.ia_prefixmask.sin6_addr)[i]) + != + (((u_char *)&sin6->sin6_addr)[i] & + ((u_char *)&ia6.ia_prefixmask.sin6_addr)[i])) + return NULL; + } + + /* After the mask check, overwrite ia6.ia_addr with sin6. */ + memcpy(&ia6.ia_addr, sin6, sizeof(ia6.ia_addr)); + return(stf_getin4addr(sin, (struct ifaddr *)&ia6, 0)); +} + +static struct sockaddr_in * +stf_getin4addr(struct sockaddr_in *sin, + struct ifaddr *ifa, + int flags) +{ + struct in_addr *in; + struct sockaddr_in6 *sin6; + struct sockaddr_in6 *sin6d; + struct in6_ifaddr *ia6; + + DEBUG_PRINTF(1, "%s: enter.\n", __func__); + if (ifa == NULL || + ifa->ifa_addr == NULL || + ifa->ifa_addr->sa_family != AF_INET6) + return NULL; + + sin6 = satosin6(ifa->ifa_addr); + ia6 = ifatoia6(ifa); + + if (ifa->ifa_dstaddr != NULL) { + switch (ifa->ifa_dstaddr->sa_family) { + case AF_INET6: + sin6d = satosin6(ifa->ifa_dstaddr); + if (IN6_IS_ADDR_UNSPECIFIED(&sin6d->sin6_addr)) + break; + if (IN6_IS_ADDR_V4COMPAT(&sin6d->sin6_addr)) { + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = + *(const u_int32_t *)(const void *)(&sin6d->sin6_addr.s6_addr[12]); + if (flags & STF_GETIN4_USE_CACHE) { + /* + * XXX: ifa_dstaddr is used as a cache of the + * extracted IPv4 address. + */ + memcpy(sin, satosin(ifa->ifa_dstaddr), sizeof(*sin)); + ifa->ifa_dstaddr->sa_family = AF_INET; + } +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + + ip_sprintf(buf, &sin->sin_addr); + DEBUG_PRINTF(1, "%s: specified dst address was used = %s\n", __func__, buf); + } +#endif + return (sin); + } else { + DEBUG_PRINTF(1, "Not a V4COMPAT address!\n"); + return (NULL); + } + /* NOT REACHED */ + break; + case AF_INET: + if (flags & STF_GETIN4_USE_CACHE) { + /* + * XXX: ifa_dstaddr is used as a cache of the + * extracted IPv4 address. + */ + memcpy(sin, satosin(ifa->ifa_dstaddr), sizeof(*sin)); + ifa->ifa_dstaddr->sa_family = AF_INET; +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + + ip_sprintf(buf, &sin->sin_addr); + DEBUG_PRINTF(1, "%s: cached address was used = %s\n", __func__, buf); + } +#endif + return (sin); + } + } + } + memset(sin, 0, sizeof(*sin)); + in = &sin->sin_addr; + +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + + ip6_sprintf(buf, &sin6->sin6_addr); + DEBUG_PRINTF(1, "%s: sin6->sin6_addr = %s\n", __func__, buf); + } +#endif + + if (IN6_IS_ADDR_6TO4(&sin6->sin6_addr)) { + /* 6to4 (RFC 3056) */ + bcopy(GET_V4(&sin6->sin6_addr), in, sizeof(*in)); + if (isrfc1918addr(in)) + return NULL; + } else { + /* 6rd (RFC 5569) */ + struct in6_addr buf; + u_char *p = (u_char *)&buf; + u_char *q = (u_char *)in; + u_int residue = 0; + u_char mask; + int i; + u_int plen; + + /* + * 6rd-relays IPv6 prefix is located at a 32-bit just + * after the prefix edge. + */ + plen = in6_mask2len(&satosin6(ifa->ifa_netmask)->sin6_addr, NULL); + if (32 < plen) + return NULL; + + memcpy(&buf, &sin6->sin6_addr, sizeof(buf)); + p += plen / 8; + residue = plen % 8; + mask = ~((u_char)(-1) >> residue); + + /* + * The p points head of the IPv4 address part in + * bytes. The residue is a bit-shift factor when + * prefixlen is not a multiple of 8. + */ + for (i = 0; i < 4; i++) { + DEBUG_PRINTF(2, "p[%d] = %d\n", i, p[i]); + DEBUG_PRINTF(2, "residue = %d\n", residue); + if (residue) { + p[i] <<= residue; + DEBUG_PRINTF(2, "p[%d] << residue = %d\n", + i, p[i]); + DEBUG_PRINTF(2, "mask = %x\n", + mask); + DEBUG_PRINTF(2, "p[%d + 1] & mask = %d\n", + i, p[i + 1] & mask); + DEBUG_PRINTF(2, "p[%d + 1] & mask >> (8 - residue) = %d\n", + i, (p[i + 1] & mask) >> (8-residue)); + p[i] |= ((p[i+1] & mask) >> (8 - residue)); + } + q[i] = p[i]; + } + } +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + + ip_sprintf(buf, in); + DEBUG_PRINTF(1, "%s: in->in_addr = %s\n", __func__, buf); + DEBUG_PRINTF(1, "%s: leave\n", __func__); + } +#endif + if (flags & STF_GETIN4_USE_CACHE) { + DEBUG_PRINTF(1, "%s: try to memset 0 to ia_dstaddr.\n", __func__); + memset(&ia6->ia_dstaddr, 0, sizeof(ia6->ia_dstaddr)); + DEBUG_PRINTF(1, "%s: try to access ifa->ifa_dstaddr.\n", __func__); + ifa->ifa_dstaddr = (struct sockaddr *)&ia6->ia_dstaddr; + DEBUG_PRINTF(1, "%s: try to memcpy ifa->ifa_dstaddr.\n", __func__); + memcpy((struct sockaddr_in *)ifa->ifa_dstaddr, + sin, sizeof(struct sockaddr_in)); + DEBUG_PRINTF(1, "%s: try to set sa_family.\n", __func__); + ifa->ifa_dstaddr->sa_family = AF_INET; + DEBUG_PRINTF(1, "%s: in->in_addr is stored in ifa_dstaddr.\n", + __func__); + } + return (sin); +} + +static void +stf_ifaddr_change(void *arg __unused, struct ifnet *ifp) +{ + struct sockaddr_in in4; + struct ifaddr *ifa; + + DEBUG_PRINTF(1, "%s: enter.\n", __func__); + + if_addr_rlock(ifp); + TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr == NULL) + continue; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + if (ifa->ifa_dstaddr != NULL) { + DEBUG_PRINTF(1, "%s: ifa->ifa_dstaddr != NULL!.\n", __func__); + +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + + ip6_sprintf(buf, &satosin6(ifa->ifa_addr)->sin6_addr); + DEBUG_PRINTF(1, "%s: ifa_addr = %s\n", __func__, buf); + } +#endif + switch (ifa->ifa_dstaddr->sa_family) { + case AF_INET: +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + + ip_sprintf(buf, &satosin(ifa->ifa_dstaddr)->sin_addr); + DEBUG_PRINTF(1, "%s: ifa_dstaddr = %s\n", __func__, buf); + } +#endif + continue; + case AF_INET6: +#if STF_DEBUG + { + char buf[INET6_ADDRSTRLEN + 1]; + memset(&buf, 0, sizeof(buf)); + + ip6_sprintf(buf, &satosin6(ifa->ifa_dstaddr)->sin6_addr); + DEBUG_PRINTF(1, "%s: ifa_dstaddr = %s\n", __func__, buf); + } +#endif + if (IN6_IS_ADDR_V4COMPAT(&satosin6(ifa->ifa_dstaddr)->sin6_addr)) { + } + if (!IN6_IS_ADDR_UNSPECIFIED(&satosin6(ifa->ifa_dstaddr)->sin6_addr)) + continue; + } + } + DEBUG_PRINTF(1, "%s: ifa->ifa_dstaddr == NULL or ::!.\n", __func__); + /* + * Extract IPv4 address from IPv6 address, + * then store it into ifa_dstaddr as the + * destination. + */ + if (stf_getin4addr(&in4, ifa, STF_GETIN4_USE_CACHE) == NULL) { + ifatoia6(ifa)->ia_flags |= IN6_IFF_DETACHED; + continue; + } + } + if_addr_runlock(ifp); +} + +static int +stf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ifaddr *ifa; struct ifreq *ifr; - struct sockaddr_in6 *sin6; - struct in_addr addr; +/* + struct in6_aliasreq *ifra6; +*/ + struct in6_aliasreq ifra; +/* + struct sockaddr_in6 *sa6; +*/ int error; + memset(&ifra, 0, sizeof(ifra)); + /* + * Sanity check: if more than two interfaces have IFF_UP, do + * if_down() for all of them except for the specified one. + */ + if (ifp->if_flags & IFF_UP) { + struct stf_softc *sc_cur = ifp->if_softc; + struct stf_softc *sc; + + mtx_lock(&stf_mtx); + LIST_FOREACH(sc, &V_stf_softc_list, stf_list) { + if (sc == sc_cur) + continue; + if ((STF2IFP(sc)->if_flags & IFF_UP) != 0) { + if_printf(STF2IFP(sc), + "marked as DOWN because at least " + "one instance of stf(4) is already " + "working.\n"); + if_down(STF2IFP(sc)); + } + } + mtx_unlock(&stf_mtx); + } + error = 0; switch (cmd) { case SIOCSIFADDR: + DEBUG_PRINTF(1, "enter SIOCSIFADDR.\n"); ifa = (struct ifaddr *)data; - if (ifa == NULL || ifa->ifa_addr->sa_family != AF_INET6) { + if (ifa == NULL) { error = EAFNOSUPPORT; break; } - sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; - if (!IN6_IS_ADDR_6TO4(&sin6->sin6_addr)) { + if (ifa->ifa_addr->sa_family == AF_INET6 && + ifa->ifa_dstaddr->sa_family == AF_INET && + ifa->ifa_netmask->sa_family == AF_INET6) { + ifa->ifa_rtrequest = stf_rtrequest; + ifp->if_flags |= IFF_UP; + } else { error = EINVAL; break; } - bcopy(GET_V4(&sin6->sin6_addr), &addr, sizeof(addr)); - if (isrfc1918addr(&addr)) { - error = EINVAL; - break; - } - - ifa->ifa_rtrequest = stf_rtrequest; - ifp->if_flags |= IFF_UP; break; - case SIOCADDMULTI: case SIOCDELMULTI: ifr = (struct ifreq *)data; diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 7ae8477..684d808 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -548,7 +548,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, * is the same as before, then the call is * un-necessarily executed here. */ - in_ifscrub(ifp, ia, LLE_STATIC); + in_ifscrub(ifp, ia, 0); ia->ia_sockmask = ifra->ifra_mask; ia->ia_sockmask.sin_family = AF_INET; ia->ia_subnetmask = @@ -557,7 +557,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, } if ((ifp->if_flags & IFF_POINTOPOINT) && (ifra->ifra_dstaddr.sin_family == AF_INET)) { - in_ifscrub(ifp, ia, LLE_STATIC); + in_ifscrub(ifp, ia, 0); ia->ia_dstaddr = ifra->ifra_dstaddr; maskIsNew = 1; /* We lie; but the effect's the same */ } @@ -1179,20 +1179,14 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags) && (ia->ia_ifp->if_type != IFT_CARP)) { ifa_ref(&ia->ia_ifa); IN_IFADDR_RUNLOCK(); - error = rtinit(&(target->ia_ifa), (int)RTM_DELETE, + rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target)); - if (error == 0) - target->ia_flags &= ~IFA_ROUTE; - else - log(LOG_INFO, "in_scrubprefix: err=%d, old prefix delete failed\n", - error); + target->ia_flags &= ~IFA_ROUTE; + error = rtinit(&ia->ia_ifa, (int)RTM_ADD, rtinitflags(ia) | RTF_UP); if (error == 0) ia->ia_flags |= IFA_ROUTE; - else - log(LOG_INFO, "in_scrubprefix: err=%d, new prefix add failed\n", - error); ifa_free(&ia->ia_ifa); return (error); } @@ -1216,12 +1210,9 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags) /* * As no-one seem to have this prefix, we can remove the route. */ - error = rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target)); - if (error == 0) - target->ia_flags &= ~IFA_ROUTE; - else - log(LOG_INFO, "in_scrubprefix: err=%d, prefix delete failed\n", error); - return (error); + rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target)); + target->ia_flags &= ~IFA_ROUTE; + return (0); } #undef rtinitflags diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index de3a622..052b8f6 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -504,13 +504,6 @@ ip6_input(struct mbuf *m) goto bad; } #endif -#ifdef IPSEC - /* - * Bypass packet filtering for packets previously handled by IPsec. - */ - if (ip6_ipsec_filtertunnel(m)) - goto passin; -#endif /* IPSEC */ /* * Run through list of hooks for input packets. diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 2b51e43..231ce94 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -1327,7 +1327,6 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) * accept_rtadv or auto_linklocal. */ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) && - !(ND.flags & ND6_IFF_IFDISABLED) && (ND.flags & (ND6_IFF_ACCEPT_RTADV | ND6_IFF_AUTO_LINKLOCAL))) ND.flags &= ~ND6_IFF_IFDISABLED; @@ -1389,8 +1388,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp) /* If no link-local address on ifp, configure */ ND_IFINFO(ifp)->flags |= ND6_IFF_AUTO_LINKLOCAL; in6_ifattach(ifp, NULL); - } else if ((ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) && - !(ND.flags & ND6_IFF_IFDISABLED)) { + } else if (ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) { /* * When the IF already has * ND6_IFF_AUTO_LINKLOCAL and no link-local diff --git a/usr.sbin/route6d/Makefile b/usr.sbin/route6d/Makefile index df23d33..51c59b8 100644 --- a/usr.sbin/route6d/Makefile +++ b/usr.sbin/route6d/Makefile @@ -6,6 +6,6 @@ MAN= route6d.8 CFLAGS+= -DHAVE_POLL_H -WARNS?= 1 +WARNS?= 6 .include <bsd.prog.mk> diff --git a/usr.sbin/route6d/route6d.8 b/usr.sbin/route6d/route6d.8 index 121f5f2..db0e70f 100644 --- a/usr.sbin/route6d/route6d.8 +++ b/usr.sbin/route6d/route6d.8 @@ -16,7 +16,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 31, 1997 +.Dd July 21, 2009 .Dt ROUTE6D 8 .Os .Sh NAME @@ -26,6 +26,15 @@ .Nm .Op Fl adDhlnqsS .Bk -words +.Op Fl p Ar pidfile +.Ek +.Bk -words +.Op Fl P Ar protonum +.Ek +.Bk -words +.Op Fl Q Ar protonum +.Ek +.Bk -words .Op Fl R Ar routelog .Ek .Bk -words @@ -62,6 +71,29 @@ statically defined routes will be removed unless corresponding updates arrive as if the routes are received at the startup of .Nm . .\" +.It Fl p Ar pidfile +This option specifies PID filename as +.Ar pidfile . +The default value is +.Pa /var/run/route6d.pid . +.It Fl P Ar protonum +This option makes the +.Nm +recognize a route with RTF_PROTO[123] flag as one with infinite lifetime. The +.Ar protonum +must be 1, 2, or 3 and they corresponds to RTF_PROTO1, RTF_PROTO2, and +RTF_PROTO3, respectively. Multiple +.Fl P +flags are allowed. +.It Fl Q Ar protonum +This option makes the +.Nm +add RTF_PROTO[123] flags to routes which are obtained via RIP sessions. The +.Ar protonum +must be 1, 2, or 3 and they corresponds to RTF_PROTO1, RTF_PROTO2, and +RTF_PROTO3, respectively. Multiple +.Fl Q +flags are allowed. .It Fl R Ar routelog This option makes the .Nm diff --git a/usr.sbin/route6d/route6d.c b/usr.sbin/route6d/route6d.c index 0205a03..761deeb 100644 --- a/usr.sbin/route6d/route6d.c +++ b/usr.sbin/route6d/route6d.c @@ -31,13 +31,14 @@ */ #ifndef lint -static char _rcsid[] = "$KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp $"; +static const char _rcsid[] = "$KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp $"; #endif #include <stdio.h> #include <time.h> #include <unistd.h> +#include <fnmatch.h> #include <stdlib.h> #include <string.h> #include <signal.h> @@ -78,6 +79,7 @@ static char _rcsid[] = "$KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp #include "route6d.h" #define MAXFILTER 40 +#define RT_DUMP_MAXRETRY 15 #ifdef DEBUG #define INIT_INTERVAL6 6 @@ -103,7 +105,7 @@ static char _rcsid[] = "$KAME: route6d.c,v 1.104 2003/10/31 00:30:20 itojun Exp } while (0) struct ifc { /* Configuration of an interface */ - char *ifc_name; /* if name */ + char ifc_name[IFNAMSIZ]; /* if name */ struct ifc *ifc_next; int ifc_index; /* if index */ int ifc_mtu; /* if mtu */ @@ -112,7 +114,6 @@ struct ifc { /* Configuration of an interface */ short ifc_cflags; /* IFC_XXX */ struct in6_addr ifc_mylladdr; /* my link-local address */ struct sockaddr_in6 ifc_ripsin; /* rip multicast address */ - struct iff *ifc_filter; /* filter structure */ struct ifac *ifc_addr; /* list of AF_INET6 addresses */ int ifc_joined; /* joined to ff02::9 */ }; @@ -126,6 +127,7 @@ struct ifac { /* Adddress associated to an interface */ }; struct iff { + char iff_name[IFNAMSIZ]; int iff_type; struct in6_addr iff_addr; int iff_plen; @@ -133,9 +135,10 @@ struct iff { }; struct ifc *ifc; +struct iff *iff_head; int nifc; /* number of valid ifc's */ struct ifc **index2ifc; -int nindex2ifc; +unsigned int nindex2ifc; struct ifc *loopifcp = NULL; /* pointing to loopback */ #ifdef HAVE_POLL_H struct pollfd set[2]; @@ -181,6 +184,8 @@ int nflag = 0; /* don't update kernel routing table */ int aflag = 0; /* age out even the statically defined routes */ int hflag = 0; /* don't split horizon */ int lflag = 0; /* exchange site local routes */ +int Pflag = 0; /* don't age out routes with RTF_PROTO[123] */ +int Qflag = RTF_PROTO2; /* set RTF_PROTO[123] flag to routes by RIPng */ int sflag = 0; /* announce static routes w/ split horizon */ int Sflag = 0; /* announce static routes to every interface */ unsigned long routetag = 0; /* route tag attached on originating case */ @@ -222,7 +227,7 @@ int out_filter(struct riprt *, struct ifc *); void init(void); void sockopt(struct ifc *); void ifconfig(void); -void ifconfig1(const char *, const struct sockaddr *, struct ifc *, int); +int ifconfig1(const char *, const struct sockaddr *, struct ifc *, int); void rtrecv(void); int rt_del(const struct sockaddr_in6 *, const struct sockaddr_in6 *, const struct sockaddr_in6 *); @@ -240,12 +245,13 @@ void applyplen(struct in6_addr *, int); void ifrtdump(int); void ifdump(int); void ifdump0(FILE *, const struct ifc *); +void ifremove(int); void rtdump(int); void rt_entry(struct rt_msghdr *, int); void rtdexit(void); void riprequest(struct ifc *, struct netinfo6 *, int, struct sockaddr_in6 *); -void ripflush(struct ifc *, struct sockaddr_in6 *); +void ripflush(struct ifc *, struct sockaddr_in6 *, int, struct netinfo6 *np); void sendrequest(struct ifc *); int sin6mask2len(const struct sockaddr_in6 *); int mask2len(const struct in6_addr *, int); @@ -276,16 +282,23 @@ void setindex2ifc(int, struct ifc *); #define MALLOC(type) ((type *)malloc(sizeof(type))) +#define IFIL_TYPE_ANY 0 +#define IFIL_TYPE_A 'A' +#define IFIL_TYPE_N 'N' +#define IFIL_TYPE_T 'T' +#define IFIL_TYPE_O 'O' +#define IFIL_TYPE_L 'L' + int -main(argc, argv) - int argc; - char **argv; +main(int argc, char *argv[]) { int ch; int error = 0; + unsigned long proto; struct ifc *ifcp; sigset_t mask, omask; - FILE *pidfile; + const char *pidfile = ROUTE6D_PID; + FILE *pidfh; char *progname; char *ep; @@ -296,7 +309,7 @@ main(argc, argv) progname = *argv; pid = getpid(); - while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnqsS")) != -1) { + while ((ch = getopt(argc, argv, "A:N:O:R:T:L:t:adDhlnp:P:Q:qsS")) != -1) { switch (ch) { case 'A': case 'N': @@ -318,6 +331,41 @@ main(argc, argv) /*NOTREACHED*/ } break; + case 'p': + pidfile = optarg; + break; + case 'P': + ep = NULL; + proto = strtoul(optarg, &ep, 0); + if (!ep || *ep != '\0' || 3 < proto) { + fatal("invalid P flag"); + /*NOTREACHED*/ + } + if (proto == 0) + Pflag = 0; + if (proto == 1) + Pflag |= RTF_PROTO1; + if (proto == 2) + Pflag |= RTF_PROTO2; + if (proto == 3) + Pflag |= RTF_PROTO3; + break; + case 'Q': + ep = NULL; + proto = strtoul(optarg, &ep, 0); + if (!ep || *ep != '\0' || 3 < proto) { + fatal("invalid Q flag"); + /*NOTREACHED*/ + } + if (proto == 0) + Qflag = 0; + if (proto == 1) + Qflag |= RTF_PROTO1; + if (proto == 2) + Qflag |= RTF_PROTO2; + if (proto == 3) + Qflag |= RTF_PROTO3; + break; case 'R': if ((rtlog = fopen(optarg, "w")) == NULL) { fatal("Can not write to routelog"); @@ -395,9 +443,9 @@ main(argc, argv) #if 1 pid = getpid(); - if ((pidfile = fopen(ROUTE6D_PID, "w")) != NULL) { - fprintf(pidfile, "%d\n", pid); - fclose(pidfile); + if ((pidfh = fopen(pidfile, "w")) != NULL) { + fprintf(pidfh, "%d\n", pid); + fclose(pidfh); } #endif @@ -428,7 +476,7 @@ main(argc, argv) alarm(ripinterval(INIT_INTERVAL6)); for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { - if (iff_find(ifcp, 'N')) + if (iff_find(ifcp, IFIL_TYPE_N)) continue; if (ifcp->ifc_index > 0 && (ifcp->ifc_flags & IFF_UP)) sendrequest(ifcp); @@ -495,8 +543,7 @@ main(argc, argv) } void -sighandler(signo) - int signo; +sighandler(int signo) { switch (signo) { @@ -520,7 +567,7 @@ sighandler(signo) */ /* ARGSUSED */ void -rtdexit() +rtdexit(void) { struct riprt *rrt; @@ -547,7 +594,7 @@ rtdexit() */ /* ARGSUSED */ void -ripalarm() +ripalarm(void) { struct ifc *ifcp; struct riprt *rrt, *rrt_prev, *rrt_next; @@ -587,7 +634,7 @@ ripalarm() } void -init() +init(void) { int error; const int int0 = 0, int1 = 1, int255 = 255; @@ -735,13 +782,8 @@ init() /* * ripflush flushes the rip datagram stored in the rip buffer */ -static int nrt; -static struct netinfo6 *np; - void -ripflush(ifcp, sin6) - struct ifc *ifcp; - struct sockaddr_in6 *sin6; +ripflush(struct ifc *ifcp, struct sockaddr_in6 *sin6, int nrt, struct netinfo6 *np) { int i; int error; @@ -783,21 +825,19 @@ ripflush(ifcp, sin6) ifcp->ifc_name, inet6_n2p(&ifcp->ifc_ripsin.sin6_addr)); ifcp->ifc_flags &= ~IFF_UP; /* As if down for AF_INET6 */ } - nrt = 0; np = ripbuf->rip6_nets; } /* * Generate RIP6_RESPONSE packets and send them. */ void -ripsend(ifcp, sin6, flag) - struct ifc *ifcp; - struct sockaddr_in6 *sin6; - int flag; +ripsend(struct ifc *ifcp, struct sockaddr_in6 *sin6, int flag) { struct riprt *rrt; struct in6_addr *nh; /* next hop */ + struct netinfo6 *np; int maxrte; + int nrt; if (qflag) return; @@ -811,7 +851,9 @@ ripsend(ifcp, sin6, flag) sizeof(struct udphdr) - sizeof(struct rip6) + sizeof(struct netinfo6)) / sizeof(struct netinfo6); - nrt = 0; np = ripbuf->rip6_nets; nh = NULL; + nh = NULL; + nrt = 0; + np = ripbuf->rip6_nets; for (rrt = riprt; rrt; rrt = rrt->rrt_next) { if (rrt->rrt_rflags & RRTF_NOADVERTISE) continue; @@ -819,12 +861,14 @@ ripsend(ifcp, sin6, flag) *np = rrt->rrt_info; np++; nrt++; if (nrt == maxrte) { - ripflush(NULL, sin6); + ripflush(NULL, sin6, nrt, np); nh = NULL; + nrt = 0; + np = ripbuf->rip6_nets; } } if (nrt) /* Send last packet */ - ripflush(NULL, sin6); + ripflush(NULL, sin6, nrt, np); return; } @@ -833,11 +877,11 @@ ripsend(ifcp, sin6, flag) return; /* -N: no use */ - if (iff_find(ifcp, 'N') != NULL) + if (iff_find(ifcp, IFIL_TYPE_N) != NULL) return; /* -T: generate default route only */ - if (iff_find(ifcp, 'T') != NULL) { + if (iff_find(ifcp, IFIL_TYPE_T) != NULL) { struct netinfo6 rrt_info; memset(&rrt_info, 0, sizeof(struct netinfo6)); rrt_info.rip6_dest = in6addr_any; @@ -848,7 +892,7 @@ ripsend(ifcp, sin6, flag) np = ripbuf->rip6_nets; *np = rrt_info; nrt = 1; - ripflush(ifcp, sin6); + ripflush(ifcp, sin6, nrt, np); return; } @@ -880,8 +924,13 @@ ripsend(ifcp, sin6, flag) !IN6_IS_ADDR_UNSPECIFIED(&rrt->rrt_gw) && (rrt->rrt_rflags & RRTF_NH_NOT_LLADDR) == 0) { if (nh == NULL || !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw)) { - if (nrt == maxrte - 2) - ripflush(ifcp, sin6); + if (nrt == maxrte - 2) { + ripflush(ifcp, sin6, nrt, np); + nh = NULL; + nrt = 0; + np = ripbuf->rip6_nets; + } + np->rip6_dest = rrt->rrt_gw; if (IN6_IS_ADDR_LINKLOCAL(&np->rip6_dest)) SET_IN6_LINKLOCAL_IFINDEX(np->rip6_dest, 0); @@ -895,8 +944,12 @@ ripsend(ifcp, sin6, flag) !IN6_ARE_ADDR_EQUAL(nh, &rrt->rrt_gw) || rrt->rrt_rflags & RRTF_NH_NOT_LLADDR)) { /* Reset nexthop */ - if (nrt == maxrte - 2) - ripflush(ifcp, sin6); + if (nrt == maxrte - 2) { + ripflush(ifcp, sin6, nrt, np); + nh = NULL; + nrt = 0; + np = ripbuf->rip6_nets; + } memset(np, 0, sizeof(struct netinfo6)); np->rip6_metric = NEXTHOP_METRIC; nh = NULL; @@ -907,21 +960,21 @@ ripsend(ifcp, sin6, flag) *np = rrt->rrt_info; np++; nrt++; if (nrt == maxrte) { - ripflush(ifcp, sin6); + ripflush(ifcp, sin6, nrt, np); nh = NULL; + nrt = 0; + np = ripbuf->rip6_nets; } } if (nrt) /* Send last packet */ - ripflush(ifcp, sin6); + ripflush(ifcp, sin6, nrt, np); } /* * outbound filter logic, per-route/interface. */ int -out_filter(rrt, ifcp) - struct riprt *rrt; - struct ifc *ifcp; +out_filter(struct riprt *rrt, struct ifc *ifcp) { struct iff *iffp; struct in6_addr ia; @@ -931,9 +984,11 @@ out_filter(rrt, ifcp) * -A: filter out less specific routes, if we have aggregated * route configured. */ - for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { + for (iffp = iff_head; iffp; iffp = iffp->iff_next) { if (iffp->iff_type != 'A') continue; + if (fnmatch(iffp->iff_name, ifcp->ifc_name, 0) != 0) + continue; if (rrt->rrt_info.rip6_plen <= iffp->iff_plen) continue; ia = rrt->rrt_info.rip6_dest; @@ -948,9 +1003,11 @@ out_filter(rrt, ifcp) */ if ((rrt->rrt_rflags & RRTF_AGGREGATE) != 0) { ok = 0; - for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { + for (iffp = iff_head; iffp; iffp = iffp->iff_next) { if (iffp->iff_type != 'A') continue; + if (fnmatch(iffp->iff_name, ifcp->ifc_name, 0) != 0) + continue; if (rrt->rrt_info.rip6_plen == iffp->iff_plen && IN6_ARE_ADDR_EQUAL(&rrt->rrt_info.rip6_dest, &iffp->iff_addr)) { @@ -965,11 +1022,13 @@ out_filter(rrt, ifcp) /* * -O: advertise only if prefix matches the configured prefix. */ - if (iff_find(ifcp, 'O')) { + if (iff_find(ifcp, IFIL_TYPE_O)) { ok = 0; - for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { + for (iffp = iff_head; iffp; iffp = iffp->iff_next) { if (iffp->iff_type != 'O') continue; + if (fnmatch(iffp->iff_name, ifcp->ifc_name, 0) != 0) + continue; if (rrt->rrt_info.rip6_plen < iffp->iff_plen) continue; ia = rrt->rrt_info.rip6_dest; @@ -992,9 +1051,7 @@ out_filter(rrt, ifcp) * It checks options specified in the arguments and the split horizon rule. */ int -tobeadv(rrt, ifcp) - struct riprt *rrt; - struct ifc *ifcp; +tobeadv(struct riprt *rrt, struct ifc *ifcp) { /* Special care for static routes */ @@ -1019,9 +1076,7 @@ tobeadv(rrt, ifcp) * Send a rip packet actually. */ int -sendpacket(sin6, len) - struct sockaddr_in6 *sin6; - int len; +sendpacket(struct sockaddr_in6 *sin6, int len) { struct msghdr m; struct cmsghdr *cm; @@ -1080,7 +1135,7 @@ sendpacket(sin6, len) * table if necessary. */ void -riprecv() +riprecv(void) { struct ifc *ifcp, *ic; struct sockaddr_in6 fsock; @@ -1147,7 +1202,7 @@ riprecv() if (idx && IN6_IS_ADDR_LINKLOCAL(&fsock.sin6_addr)) SET_IN6_LINKLOCAL_IFINDEX(fsock.sin6_addr, idx); - if (len < sizeof(struct rip6)) { + if ((size_t)len < sizeof(struct rip6)) { trace(1, "Packet too short\n"); return; } @@ -1235,7 +1290,7 @@ riprecv() } /* -N: no use */ - if (iff_find(ifcp, 'N') != NULL) + if (iff_find(ifcp, IFIL_TYPE_N) != NULL) return; tracet(1, "Recv(%s): from %s.%d info(%d)\n", @@ -1301,8 +1356,10 @@ riprecv() * -L: listen only if the prefix matches the configuration */ ok = 1; /* if there's no L filter, it is ok */ - for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { - if (iffp->iff_type != 'L') + for (iffp = iff_head; iffp; iffp = iffp->iff_next) { + if (iffp->iff_type != IFIL_TYPE_L) + continue; + if (fnmatch(iffp->iff_name, ifcp->ifc_name, 0) != 0) continue; ok = 0; if (np->rip6_plen < iffp->iff_plen) @@ -1429,8 +1486,7 @@ riprecv() * Send all routes request packet to the specified interface. */ void -sendrequest(ifcp) - struct ifc *ifcp; +sendrequest(struct ifc *ifcp) { struct netinfo6 *np; int error; @@ -1458,11 +1514,10 @@ sendrequest(ifcp) * Process a RIP6_REQUEST packet. */ void -riprequest(ifcp, np, nn, sin6) - struct ifc *ifcp; - struct netinfo6 *np; - int nn; - struct sockaddr_in6 *sin6; +riprequest(struct ifc *ifcp, + struct netinfo6 *np, + int nn, + struct sockaddr_in6 *sin6) { int i; struct riprt *rrt; @@ -1490,7 +1545,7 @@ riprequest(ifcp, np, nn, sin6) * Get information of each interface. */ void -ifconfig() +ifconfig(void) { struct ifaddrs *ifap, *ifa; struct ifc *ifcp; @@ -1525,9 +1580,8 @@ ifconfig() ifcp->ifc_next = ifc; ifc = ifcp; nifc++; - ifcp->ifc_name = allocopy(ifa->ifa_name); + strlcpy(ifcp->ifc_name, ifa->ifa_name, sizeof(ifcp->ifc_name)); ifcp->ifc_addr = 0; - ifcp->ifc_filter = 0; ifcp->ifc_flags = ifa->ifa_flags; trace(1, "newif %s <%s>\n", ifcp->ifc_name, ifflags(ifcp->ifc_flags)); @@ -1543,7 +1597,10 @@ ifconfig() } ifcp->ifc_flags = ifa->ifa_flags; } - ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s); + if (ifconfig1(ifa->ifa_name, ifa->ifa_addr, ifcp, s) < 0) { + /* maybe temporary failure */ + continue; + } if ((ifcp->ifc_flags & (IFF_LOOPBACK | IFF_UP)) == IFF_UP && 0 < ifcp->ifc_index && !ifcp->ifc_joined) { mreq.ipv6mr_multiaddr = ifcp->ifc_ripsin.sin6_addr; @@ -1561,12 +1618,11 @@ ifconfig() freeifaddrs(ifap); } -void -ifconfig1(name, sa, ifcp, s) - const char *name; - const struct sockaddr *sa; - struct ifc *ifcp; - int s; +int +ifconfig1(const char *name, + const struct sockaddr *sa, + struct ifc *ifcp, + int s) { struct in6_ifreq ifr; const struct sockaddr_in6 *sin6; @@ -1576,19 +1632,19 @@ ifconfig1(name, sa, ifcp, s) sin6 = (const struct sockaddr_in6 *)sa; if (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) && !lflag) - return; + return -1; ifr.ifr_addr = *sin6; strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr) < 0) { - fatal("ioctl: SIOCGIFNETMASK_IN6"); - /*NOTREACHED*/ + syslog(LOG_INFO, "ioctl: SIOCGIFNETMASK_IN6"); + return -1; } plen = sin6mask2len(&ifr.ifr_addr); if ((ifa = ifa_match(ifcp, &sin6->sin6_addr, plen)) != NULL) { /* same interface found */ /* need check if something changed */ /* XXX not yet implemented */ - return; + return -1; } /* * New address is found @@ -1636,6 +1692,38 @@ ifconfig1(name, sa, ifcp, s) ifcp->ifc_index, ifcp->ifc_mtu, ifcp->ifc_metric); } else ifcp->ifc_cflags |= IFC_CHANGED; + + return 0; +} + +void +ifremove(int ifindex) +{ + struct ifc *ifcp; + struct ifc *ifcp_prev = NULL; + struct riprt *rrt; + + for (ifcp = ifc; ifcp; ifcp = ifcp->ifc_next) { + if (ifcp->ifc_index == ifindex) + break; + ifcp_prev = ifcp; + } + if (ifcp == NULL) + return; + + tracet(1, "ifremove: %s is departed.\n", ifcp->ifc_name); + if (ifcp_prev == NULL) { + ifc = ifcp->ifc_next; + } else { + ifcp_prev->ifc_next = ifcp->ifc_next; + } + + for (rrt = riprt; rrt; rrt = rrt->rrt_next) { + if (rrt->rrt_index == ifcp->ifc_index && + rrt->rrt_rflags & RRTF_AGGREGATE) + delroute(&rrt->rrt_info, &rrt->rrt_gw); + } + free(ifcp); } /* @@ -1643,30 +1731,35 @@ ifconfig1(name, sa, ifcp, s) * Update interface information as necesssary. */ void -rtrecv() +rtrecv(void) { char buf[BUFSIZ]; - char *p, *q; + char *p, *q = NULL; struct rt_msghdr *rtm; struct ifa_msghdr *ifam; struct if_msghdr *ifm; + struct if_announcemsghdr *ifan; int len; struct ifc *ifcp, *ic; int iface = 0, rtable = 0; struct sockaddr_in6 *rta[RTAX_MAX]; struct sockaddr_in6 mask; - int i, addrs; + int i, addrs = 0; struct riprt *rrt; if ((len = read(rtsock, buf, sizeof(buf))) < 0) { perror("read from rtsock"); exit(1); } + if (len == 0) + return; +#if 0 if (len < sizeof(*rtm)) { trace(1, "short read from rtsock: %d (should be > %lu)\n", len, (u_long)sizeof(*rtm)); return; } +#endif if (dflag >= 2) { fprintf(stderr, "rtmsg:\n"); for (i = 0; i < len; i++) { @@ -1677,6 +1770,9 @@ rtrecv() } for (p = buf; p - buf < len; p += ((struct rt_msghdr *)p)->rtm_msglen) { + if (((struct rt_msghdr *)p)->rtm_version != RTM_VERSION) + continue; + /* safety against bogus message */ if (((struct rt_msghdr *)p)->rtm_msglen <= 0) { trace(1, "bogus rtmsg: length=%d\n", @@ -1698,6 +1794,18 @@ rtrecv() addrs = ifm->ifm_addrs; q = (char *)(ifm + 1); break; + case RTM_IFANNOUNCE: + ifan = (struct if_announcemsghdr *)p; + switch (ifan->ifan_what) { + case IFAN_ARRIVAL: + iface++; + break; + case IFAN_DEPARTURE: + ifremove(ifan->ifan_index); + iface++; + break; + } + break; default: rtm = (struct rt_msghdr *)p; addrs = rtm->rtm_addrs; @@ -1874,10 +1982,9 @@ rtrecv() * remove specified route from the internal routing table. */ int -rt_del(sdst, sgw, smask) - const struct sockaddr_in6 *sdst; - const struct sockaddr_in6 *sgw; - const struct sockaddr_in6 *smask; +rt_del(const struct sockaddr_in6 *sdst, + const struct sockaddr_in6 *sgw, + const struct sockaddr_in6 *smask) { const struct in6_addr *dst = NULL; const struct in6_addr *gw = NULL; @@ -1973,10 +2080,9 @@ rt_del(sdst, sgw, smask) * remove specified address from internal interface/routing table. */ int -rt_deladdr(ifcp, sifa, smask) - struct ifc *ifcp; - const struct sockaddr_in6 *sifa; - const struct sockaddr_in6 *smask; +rt_deladdr(struct ifc *ifcp, + const struct sockaddr_in6 *sifa, + const struct sockaddr_in6 *smask) { const struct in6_addr *addr = NULL; int prefix; @@ -2085,9 +2191,7 @@ rt_deladdr(ifcp, sifa, smask) * list. */ int -ifrt(ifcp, again) - struct ifc *ifcp; - int again; +ifrt(struct ifc *ifcp, int again) { struct ifac *ifa; struct riprt *rrt = NULL, *search_rrt, *prev_rrt, *loop_rrt; @@ -2202,9 +2306,7 @@ ifrt(ifcp, again) * since BSD kernels do not look at prefix length on p2p interfaces. */ void -ifrt_p2p(ifcp, again) - struct ifc *ifcp; - int again; +ifrt_p2p(struct ifc *ifcp, int again) { struct ifac *ifa; struct riprt *rrt, *orrt, *prevrrt; @@ -2372,8 +2474,7 @@ ifrt_p2p(ifcp, again) } int -getifmtu(ifindex) - int ifindex; +getifmtu(int ifindex) { int mib[6]; char *buf; @@ -2410,8 +2511,7 @@ getifmtu(ifindex) } const char * -rttypes(rtm) - struct rt_msghdr *rtm; +rttypes(struct rt_msghdr *rtm) { #define RTTYPE(s, f) \ do { \ @@ -2454,8 +2554,7 @@ do { \ } const char * -rtflags(rtm) - struct rt_msghdr *rtm; +rtflags(struct rt_msghdr *rtm) { static char buf[BUFSIZ]; @@ -2524,8 +2623,7 @@ do { \ } const char * -ifflags(flags) - int flags; +ifflags(int flags) { static char buf[BUFSIZ]; @@ -2564,8 +2662,7 @@ do { \ } void -krtread(again) - int again; +krtread(int again) { int mib[6]; size_t msize; @@ -2583,6 +2680,8 @@ krtread(again) mib[4] = NET_RT_DUMP; /* Dump the kernel routing table */ mib[5] = 0; /* No flags */ do { + if (retry) + sleep(1); retry++; errmsg = NULL; if (buf) @@ -2599,7 +2698,7 @@ krtread(again) errmsg = "sysctl NET_RT_DUMP"; continue; } - } while (retry < 5 && errmsg != NULL); + } while (retry < RT_DUMP_MAXRETRY && errmsg != NULL); if (errmsg) { fatal("%s (with %d retries, msize=%lu)", errmsg, retry, (u_long)msize); @@ -2616,16 +2715,14 @@ krtread(again) } void -rt_entry(rtm, again) - struct rt_msghdr *rtm; - int again; +rt_entry(struct rt_msghdr *rtm, int again) { struct sockaddr_in6 *sin6_dst, *sin6_gw, *sin6_mask; struct sockaddr_in6 *sin6_genmask, *sin6_ifp; char *rtmp, *ifname = NULL; struct riprt *rrt, *orrt; struct netinfo6 *np; - int s; + int ifindex; sin6_dst = sin6_gw = sin6_mask = sin6_genmask = sin6_ifp = 0; if ((rtm->rtm_flags & RTF_UP) == 0 || rtm->rtm_flags & @@ -2641,6 +2738,9 @@ rt_entry(rtm, again) if (rtm->rtm_flags & RTF_CLONED) return; #endif + /* XXX: Ignore connected routes. */ + if (!(rtm->rtm_flags & (RTF_GATEWAY|RTF_HOST|RTF_STATIC))) + return; /* * do not look at dynamic routes. * netbsd/openbsd cloned routes have UGHD. @@ -2690,6 +2790,8 @@ rt_entry(rtm, again) rrt->rrt_t = time(NULL); if (aflag == 0 && (rtm->rtm_flags & RTF_STATIC)) rrt->rrt_t = 0; /* Don't age static routes */ + if (rtm->rtm_flags & Pflag) + rrt->rrt_t = 0; /* Don't age PROTO[123] routes */ if ((rtm->rtm_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST) rrt->rrt_t = 0; /* Don't age non-gateway host routes */ np->rip6_tag = 0; @@ -2735,16 +2837,16 @@ rt_entry(rtm, again) trace(1, " gw %s", inet6_n2p(&rrt->rrt_gw)); /* Interface */ - s = rtm->rtm_index; - if (s < nindex2ifc && index2ifc[s]) - ifname = index2ifc[s]->ifc_name; + ifindex = rtm->rtm_index; + if ((unsigned int)ifindex < nindex2ifc && index2ifc[ifindex]) + ifname = index2ifc[ifindex]->ifc_name; else { trace(1, " not configured\n"); free(rrt); return; } - trace(1, " if %s sock %d", ifname, s); - rrt->rrt_index = s; + trace(1, " if %s sock %d", ifname, ifindex); + rrt->rrt_index = ifindex; trace(1, "\n"); @@ -2775,10 +2877,9 @@ rt_entry(rtm, again) } int -addroute(rrt, gw, ifcp) - struct riprt *rrt; - const struct in6_addr *gw; - struct ifc *ifcp; +addroute(struct riprt *rrt, + const struct in6_addr *gw, + struct ifc *ifcp) { struct netinfo6 *np; u_char buf[BUFSIZ], buf1[BUFSIZ], buf2[BUFSIZ]; @@ -2806,6 +2907,7 @@ addroute(rrt, gw, ifcp) rtm->rtm_seq = ++seq; rtm->rtm_pid = pid; rtm->rtm_flags = rrt->rrt_flags; + rtm->rtm_flags |= Qflag; rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; rtm->rtm_rmx.rmx_hopcount = np->rip6_metric - 1; rtm->rtm_inits = RTV_HOPCOUNT; @@ -2848,9 +2950,7 @@ addroute(rrt, gw, ifcp) } int -delroute(np, gw) - struct netinfo6 *np; - struct in6_addr *gw; +delroute(struct netinfo6 *np, struct in6_addr *gw) { u_char buf[BUFSIZ], buf2[BUFSIZ]; struct rt_msghdr *rtm; @@ -2873,6 +2973,7 @@ delroute(np, gw) rtm->rtm_seq = ++seq; rtm->rtm_pid = pid; rtm->rtm_flags = RTF_UP | RTF_GATEWAY; + rtm->rtm_flags |= Qflag; if (np->rip6_plen == sizeof(struct in6_addr) * 8) rtm->rtm_flags |= RTF_HOST; rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; @@ -2915,9 +3016,7 @@ delroute(np, gw) } struct in6_addr * -getroute(np, gw) - struct netinfo6 *np; - struct in6_addr *gw; +getroute(struct netinfo6 *np, struct in6_addr *gw) { u_char buf[BUFSIZ]; int myseq; @@ -2964,8 +3063,7 @@ getroute(np, gw) } const char * -inet6_n2p(p) - const struct in6_addr *p; +inet6_n2p(const struct in6_addr *p) { static char buf[BUFSIZ]; @@ -2973,8 +3071,7 @@ inet6_n2p(p) } void -ifrtdump(sig) - int sig; +ifrtdump(int sig) { ifdump(sig); @@ -2982,8 +3079,7 @@ ifrtdump(sig) } void -ifdump(sig) - int sig; +ifdump(int sig) { struct ifc *ifcp; FILE *dump; @@ -3003,10 +3099,11 @@ ifdump(sig) if (i == 0) { if ((ifcp->ifc_flags & IFF_UP) == 0) continue; - if (iff_find(ifcp, 'N') != NULL) + if (iff_find(ifcp, IFIL_TYPE_N) != NULL) continue; } else { - if (ifcp->ifc_flags & IFF_UP) + if ((ifcp->ifc_flags & IFF_UP) && + iff_find(ifcp, IFIL_TYPE_N) == NULL) continue; } ifdump0(dump, ifcp); @@ -3018,9 +3115,7 @@ ifdump(sig) } void -ifdump0(dump, ifcp) - FILE *dump; - const struct ifc *ifcp; +ifdump0(FILE *dump, const struct ifc *ifcp) { struct ifac *ifa; struct iff *iffp; @@ -3045,20 +3140,22 @@ ifdump0(dump, ifcp) ifa->ifa_plen); } } - if (ifcp->ifc_filter) { + if (1) { fprintf(dump, "\tFilter:"); - for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { + for (iffp = iff_head; iffp; iffp = iffp->iff_next) { + if (fnmatch(iffp->iff_name, ifcp->ifc_name, 0) != 0) + continue; addr = 0; switch (iffp->iff_type) { - case 'A': + case IFIL_TYPE_A: ft = "Aggregate"; addr++; break; - case 'N': + case IFIL_TYPE_N: ft = "No-use"; break; - case 'O': + case IFIL_TYPE_O: ft = "Advertise-only"; addr++; break; - case 'T': + case IFIL_TYPE_T: ft = "Default-only"; break; - case 'L': + case IFIL_TYPE_L: ft = "Listen-only"; addr++; break; default: snprintf(buf, sizeof(buf), "Unknown-%c", iffp->iff_type); @@ -3077,8 +3174,7 @@ ifdump0(dump, ifcp) } void -rtdump(sig) - int sig; +rtdump(int sig) { struct riprt *rrt; char buf[BUFSIZ]; @@ -3127,12 +3223,12 @@ rtdump(sig) * -O 5f09:c400::/32,ef0,ef1 (only when match) */ void -filterconfig() +filterconfig(void) { int i; char *p, *ap, *iflp, *ifname, *ep; - struct iff ftmp, *iff_obj; - struct ifc *ifcp; + struct iff ftmp, *iffp; + struct ifc ctmp, *ifcp; struct riprt *rrt; #if 0 struct in6_addr gw; @@ -3143,7 +3239,8 @@ filterconfig() ap = filter[i]; iflp = NULL; ifcp = NULL; - if (filtertype[i] == 'N' || filtertype[i] == 'T') { + memset(&ftmp, 0, sizeof(ftmp)); + if (filtertype[i] == IFIL_TYPE_N || filtertype[i] == IFIL_TYPE_T) { iflp = ap; goto ifonly; } @@ -3181,21 +3278,19 @@ ifonly: ifname = iflp; if ((iflp = strchr(iflp, ',')) != NULL) *iflp++ = '\0'; - ifcp = ifc_find(ifname); - if (ifcp == NULL) { - fatal("no interface %s exists", ifname); - /*NOTREACHED*/ - } - iff_obj = (struct iff *)malloc(sizeof(struct iff)); - if (iff_obj == NULL) { - fatal("malloc of iff_obj"); + strlcpy(ctmp.ifc_name, ifname, sizeof(ctmp.ifc_name)); + strlcpy(ftmp.iff_name, ifname, sizeof(ftmp.iff_name)); +#if 0 + syslog(LOG_INFO, "Add filter: type %d, ifname %s.", ftmp.iff_type, ifname); +#endif + iffp = malloc(sizeof(struct iff)); + if (iffp == NULL) { + fatal("malloc of iff"); /*NOTREACHED*/ } - memcpy((void *)iff_obj, (void *)&ftmp, - sizeof(struct iff)); - /* link it to the interface filter */ - iff_obj->iff_next = ifcp->ifc_filter; - ifcp->ifc_filter = iff_obj; + ftmp.iff_next = iff_head; + iff_head = iffp; + memcpy(iffp, &ftmp, sizeof(struct iff)); } /* @@ -3243,7 +3338,7 @@ ifonly: riprt = rrt; trace(1, "Aggregate: %s/%d for %s\n", inet6_n2p(&ftmp.iff_addr), ftmp.iff_plen, - ifcp->ifc_name); + ftmp.iff_name); /* Add this route to the kernel */ if (nflag) /* do not modify kernel routing table */ continue; @@ -3258,10 +3353,9 @@ ifonly: * with the address and prefix length specified in the arguments. */ struct ifac * -ifa_match(ifcp, ia, plen) - const struct ifc *ifcp; - const struct in6_addr *ia; - int plen; +ifa_match(const struct ifc *ifcp, + const struct in6_addr *ia, + int plen) { struct ifac *ifa; @@ -3279,9 +3373,7 @@ ifa_match(ifcp, ia, plen) * Note: This is not a rtalloc(). Therefore exact match is necessary. */ struct riprt * -rtsearch(np, prev_rrt) - struct netinfo6 *np; - struct riprt **prev_rrt; +rtsearch(struct netinfo6 *np, struct riprt **prev_rrt) { struct riprt *rrt; @@ -3301,8 +3393,7 @@ rtsearch(np, prev_rrt) } int -sin6mask2len(sin6) - const struct sockaddr_in6 *sin6; +sin6mask2len(const struct sockaddr_in6 *sin6) { return mask2len(&sin6->sin6_addr, @@ -3310,9 +3401,7 @@ sin6mask2len(sin6) } int -mask2len(addr, lenlim) - const struct in6_addr *addr; - int lenlim; +mask2len(const struct in6_addr *addr, int lenlim) { int i = 0, j; const u_char *p = (const u_char *)addr; @@ -3339,8 +3428,7 @@ mask2len(addr, lenlim) } void -applymask(addr, mask) - struct in6_addr *addr, *mask; +applymask(struct in6_addr *addr, struct in6_addr *mask) { int i; u_long *p, *q; @@ -3355,9 +3443,7 @@ static const u_char plent[8] = { }; void -applyplen(ia, plen) - struct in6_addr *ia; - int plen; +applyplen(struct in6_addr *ia, int plen) { u_char *p; int i; @@ -3377,8 +3463,7 @@ static const int pl2m[9] = { }; struct in6_addr * -plen2mask(n) - int n; +plen2mask(int n) { static struct in6_addr ia; u_char *p; @@ -3398,8 +3483,7 @@ plen2mask(n) } char * -allocopy(p) - char *p; +allocopy(char *p) { int len = strlen(p) + 1; char *q = (char *)malloc(len); @@ -3414,7 +3498,7 @@ allocopy(p) } char * -hms() +hms(void) { static char buf[BUFSIZ]; time_t t; @@ -3433,8 +3517,7 @@ hms() #define RIPRANDDEV 1.0 /* 30 +- 15, max - min = 30 */ int -ripinterval(timer) - int timer; +ripinterval(int timer) { double r = rand(); @@ -3444,7 +3527,7 @@ ripinterval(timer) } time_t -ripsuptrig() +ripsuptrig(void) { time_t t; @@ -3554,7 +3637,7 @@ trace(level, fmt, va_alist) } unsigned int -if_maxindex() +if_maxindex(void) { struct if_nameindex *p, *p0; unsigned int max = 0; @@ -3569,8 +3652,7 @@ if_maxindex() } struct ifc * -ifc_find(name) - char *name; +ifc_find(char *name) { struct ifc *ifcp; @@ -3582,23 +3664,23 @@ ifc_find(name) } struct iff * -iff_find(ifcp, type) - struct ifc *ifcp; - int type; +iff_find(struct ifc *ifcp, int type) { struct iff *iffp; - for (iffp = ifcp->ifc_filter; iffp; iffp = iffp->iff_next) { - if (iffp->iff_type == type) - return iffp; + for (iffp = iff_head; iffp; iffp = iffp->iff_next) { + if (fnmatch(iffp->iff_name, ifcp->ifc_name, 0) == 0) { + if (type == IFIL_TYPE_ANY || + type == iffp->iff_type) { + return iffp; + } + } } return NULL; } void -setindex2ifc(idx, ifcp) - int idx; - struct ifc *ifcp; +setindex2ifc(int idx, struct ifc *ifcp) { int n, nsize; struct ifc **p; diff --git a/usr.sbin/rpc.yppasswdd/Makefile b/usr.sbin/rpc.yppasswdd/Makefile index b6a0a8c..2f01e28 100644 --- a/usr.sbin/rpc.yppasswdd/Makefile +++ b/usr.sbin/rpc.yppasswdd/Makefile @@ -5,12 +5,20 @@ RPCDIR= ${DESTDIR}/usr/include/rpcsvc .PATH: ${.CURDIR}/../../usr.sbin/ypserv ${.CURDIR}/../../usr.bin/chpass \ ${.CURDIR}/../../libexec/ypxfr ${RPCDIR} +.include <bsd.own.mk> + PROG= rpc.yppasswdd SCRIPTS=yppwupdate SCRIPTSDIR= /usr/libexec MAN= rpc.yppasswdd.8 SRCS= util.c yp_access.c yp_dblookup.c yp_dbwrite.c \ yp_error.c yppasswdd_main.c yppasswdd_server.c ypxfr_misc.c ${GENSRCS} +.if ${MK_INET_SUPPORT} != "no" +SRCS+= yp_access_inet.c +.endif +.if ${MK_INET6_SUPPORT} != "no" +SRCS+= yp_access_inet6.c +.endif GENSRCS=yp.h yp_clnt.c yppasswd.h yppasswd_private.h yppasswd_private_svc.c \ yppasswd_private_xdr.c yppasswd_svc.c diff --git a/usr.sbin/rpc.yppasswdd/yppasswdd_extern.h b/usr.sbin/rpc.yppasswdd/yppasswdd_extern.h index db15be2..901b75f 100644 --- a/usr.sbin/rpc.yppasswdd/yppasswdd_extern.h +++ b/usr.sbin/rpc.yppasswdd/yppasswdd_extern.h @@ -46,8 +46,6 @@ #define MAP_UPDATE "yppwupdate" #define MAP_UPDATE_PATH YPLIBDIR "yppwupdate" -extern char *yp_dir; -extern char *progname; extern void do_master(void); extern void yppasswdprog_1(struct svc_req *, register SVCXPRT *); extern void master_yppasswdprog_1(struct svc_req *, register SVCXPRT *); diff --git a/usr.sbin/rpc.yppasswdd/yppasswdd_main.c b/usr.sbin/rpc.yppasswdd/yppasswdd_main.c index 8c89691..2311384 100644 --- a/usr.sbin/rpc.yppasswdd/yppasswdd_main.c +++ b/usr.sbin/rpc.yppasswdd/yppasswdd_main.c @@ -86,10 +86,8 @@ static int _rpcfdtype; static char _localhost[] = "localhost"; static char _passwd_byname[] = "passwd.byname"; extern int _rpcsvcstate; /* Set when a request is serviced */ -static char _progname[] = "rpc.yppasswdd"; -char *progname = _progname; -static char _yp_dir[] = _PATH_YP; -char *yp_dir = _yp_dir; +const char *progname = "rpc.yppasswdd"; +const char *yp_dir = _PATH_YP; static char _passfile_default[] = _PATH_YP "master.passwd"; char *passfile_default = _passfile_default; char *passfile; diff --git a/usr.sbin/rpc.ypupdated/ypupdated_main.c b/usr.sbin/rpc.ypupdated/ypupdated_main.c index c13af7d..f02ad24 100644 --- a/usr.sbin/rpc.ypupdated/ypupdated_main.c +++ b/usr.sbin/rpc.ypupdated/ypupdated_main.c @@ -75,8 +75,8 @@ static int _rpcfdtype; extern int _rpcsvcstate; /* Set when a request is serviced */ -char *progname = "rpc.ypupdated"; -char *yp_dir = "/var/yp/"; +const char *progname = "rpc.ypupdated"; +const char *yp_dir = _PATH_YP; static void _msgout(char* msg) diff --git a/usr.sbin/rpc.ypxfrd/Makefile b/usr.sbin/rpc.ypxfrd/Makefile index ee9e242..3b5478c 100644 --- a/usr.sbin/rpc.ypxfrd/Makefile +++ b/usr.sbin/rpc.ypxfrd/Makefile @@ -1,13 +1,21 @@ # $FreeBSD$ -.PATH: ${.CURDIR}/../../usr.sbin/ypserv +.PATH: ${.CURDIR}/../ypserv + +.include <bsd.own.mk> PROG= rpc.ypxfrd MAN= rpc.ypxfrd.8 SRCS= ypxfrd_svc.c ypxfrd.h ypxfrd_server.c yp_error.c \ yp_access.c ypxfrd_main.c - -CFLAGS+= -I. -DXFRBLOCKSIZE=65535 +.if ${MK_INET_SUPPORT} != "no" +SRCS+= yp_access_inet.c +.endif +.if ${MK_INET6_SUPPORT} != "no" +SRCS+= yp_access_inet6.c +.endif + +CFLAGS+= -I. -I${.CURDIR}/../ypserv -DXFRBLOCKSIZE=65535 WARNS?= 2 diff --git a/usr.sbin/rpc.ypxfrd/ypxfrd_extern.h b/usr.sbin/rpc.ypxfrd/ypxfrd_extern.h index 5aba934..ba4259c 100644 --- a/usr.sbin/rpc.ypxfrd/ypxfrd_extern.h +++ b/usr.sbin/rpc.ypxfrd/ypxfrd_extern.h @@ -42,9 +42,4 @@ extern int forked; extern int children; -extern void load_securenets(void); -extern void yp_error(const char *, ...); -extern int yp_access(const char *, const struct svc_req *); -extern int yp_validdomain(const char *); -extern char *yp_dir; extern void ypxfrd_freebsd_prog_1(struct svc_req *, register SVCXPRT *); diff --git a/usr.sbin/rpc.ypxfrd/ypxfrd_main.c b/usr.sbin/rpc.ypxfrd/ypxfrd_main.c index 8fa3e22..8970497 100644 --- a/usr.sbin/rpc.ypxfrd/ypxfrd_main.c +++ b/usr.sbin/rpc.ypxfrd/ypxfrd_main.c @@ -52,10 +52,12 @@ __FBSDID("$FreeBSD$"); #include <sys/socket.h> #include <netinet/in.h> #include <syslog.h> -#include "ypxfrd_extern.h" #include <sys/wait.h> #include <errno.h> +#include "ypxfrd_extern.h" +#include "yp_extern.h" + #ifndef SIG_PF #define SIG_PF void(*)(int) #endif @@ -76,8 +78,8 @@ static int _rpcfdtype; extern int _rpcsvcstate; /* Set when a request is serviced */ -char *progname = "rpc.ypxfrd"; -char *yp_dir = "/var/yp/"; +const char *progname = "rpc.ypxfrd"; +const char *yp_dir = _PATH_YP; static void _msgout(char *msg) diff --git a/usr.sbin/rpc.ypxfrd/ypxfrd_server.c b/usr.sbin/rpc.ypxfrd/ypxfrd_server.c index 5f60712..401711e 100644 --- a/usr.sbin/rpc.ypxfrd/ypxfrd_server.c +++ b/usr.sbin/rpc.ypxfrd/ypxfrd_server.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include <sys/fcntl.h> #include <machine/endian.h> #include "ypxfrd_extern.h" +#include "yp_extern.h" int forked = 0; int children = 0; diff --git a/usr.sbin/rtadvd/Makefile b/usr.sbin/rtadvd/Makefile index 9dbfc99..e34aa3c 100644 --- a/usr.sbin/rtadvd/Makefile +++ b/usr.sbin/rtadvd/Makefile @@ -23,6 +23,6 @@ LDADD= -lutil CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DROUTEINFO -WARNS?= 1 +WARNS?= 6 .include <bsd.prog.mk> diff --git a/usr.sbin/rtsold/Makefile b/usr.sbin/rtsold/Makefile index efc322c..9e2b480 100644 --- a/usr.sbin/rtsold/Makefile +++ b/usr.sbin/rtsold/Makefile @@ -19,7 +19,7 @@ MAN= rtsold.8 MLINKS= rtsold.8 rtsol.8 SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c -WARNS?= 3 +WARNS?= 6 CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H DPADD= ${LIBKVM} LDADD= -lkvm diff --git a/usr.sbin/rtsold/rtsold.c b/usr.sbin/rtsold/rtsold.c index 94046a1..73c027f 100644 --- a/usr.sbin/rtsold/rtsold.c +++ b/usr.sbin/rtsold/rtsold.c @@ -189,9 +189,9 @@ main(int argc, char **argv) if (!fflag) { char *ident; - ident = strrchr(argv0, '/'); + ident = strrchr(argv[0], '/'); if (!ident) - ident = argv0; + ident = argv[0]; else ident++; openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON); diff --git a/usr.sbin/yp_mkdb/yp_mkdb.c b/usr.sbin/yp_mkdb/yp_mkdb.c index 6c3014b..fdbb466 100644 --- a/usr.sbin/yp_mkdb/yp_mkdb.c +++ b/usr.sbin/yp_mkdb/yp_mkdb.c @@ -49,7 +49,7 @@ __FBSDID("$FreeBSD$"); #include "yp_extern.h" #include "ypxfr_extern.h" -char *yp_dir = ""; /* No particular default needed. */ +const char *yp_dir = _PATH_YP; int _rpcpmstart = 0; int debug = 1; diff --git a/usr.sbin/yppush/Makefile b/usr.sbin/yppush/Makefile index 887a80b..4ca3635 100644 --- a/usr.sbin/yppush/Makefile +++ b/usr.sbin/yppush/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ RPCDIR= ${.CURDIR}/../../include/rpcsvc -.PATH: ${RPCDIR} ${.CURDIR}/../../usr.sbin/ypserv \ +.PATH: ${RPCDIR} ${.CURDIR}/../ypserv \ ${.CURDIR}/../../libexec/ypxfr PROG= yppush diff --git a/usr.sbin/yppush/yppush_main.c b/usr.sbin/yppush/yppush_main.c index df1dbe4..3749d3e 100644 --- a/usr.sbin/yppush/yppush_main.c +++ b/usr.sbin/yppush/yppush_main.c @@ -53,10 +53,10 @@ __FBSDID("$FreeBSD$"); #include "ypxfr_extern.h" #include "yppush_extern.h" -char *progname = "yppush"; int debug = 1; int _rpcpmstart = 0; -char *yp_dir = _PATH_YP; +const char *progname = "yppush"; +const char *yp_dir = _PATH_YP; char *yppush_mapname = NULL; /* Map to transfer. */ char *yppush_domain = NULL; /* Domain in which map resides. */ diff --git a/usr.sbin/ypserv/Makefile b/usr.sbin/ypserv/Makefile index 73a6195..d3dd1fa 100644 --- a/usr.sbin/ypserv/Makefile +++ b/usr.sbin/ypserv/Makefile @@ -3,14 +3,22 @@ RPCDIR= ${.CURDIR}/../../include/rpcsvc .PATH: ${RPCDIR} +.include <bsd.own.mk> + PROG= ypserv MAN= ypserv.8 ypinit.8 SRCS= yp_svc.c yp_server.c yp_dblookup.c yp_dnslookup.c \ ypxfr_clnt.c yp.h yp_main.c yp_error.c yp_access.c yp_svc_udp.c +.if ${MK_INET_SUPPORT} != "no" +SRCS+= yp_access_inet.c +.endif +.if ${MK_INET6_SUPPORT} != "no" +SRCS+= yp_access_inet6.c +.endif CFLAGS+= -DDB_CACHE -DTCP_WRAPPER -I. -WARNS?= 0 +WARNS?= 6 DPADD= ${LIBWRAP} LDADD= -lwrap diff --git a/usr.sbin/ypserv/yp_access.c b/usr.sbin/ypserv/yp_access.c index 66d056b..5d754e0 100644 --- a/usr.sbin/ypserv/yp_access.c +++ b/usr.sbin/ypserv/yp_access.c @@ -34,31 +34,36 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); -#include <stdlib.h> +#include <sys/fcntl.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> #include <rpc/rpc.h> #include <rpcsvc/yp.h> #include <rpcsvc/yppasswd.h> #include <rpcsvc/ypxfrd.h> -#include <sys/types.h> -#include <limits.h> -#include <db.h> -#include <sys/socket.h> -#include <netinet/in.h> #include <arpa/inet.h> -#include <sys/stat.h> -#include <sys/fcntl.h> -#include <paths.h> +#include <netinet/in.h> +#include <db.h> #include <errno.h> -#include <sys/param.h> +#include <limits.h> +#include <netdb.h> +#include <paths.h> +#include <stdlib.h> + #include "yp_extern.h" #ifdef TCP_WRAPPER #include "tcpd.h" +extern int hosts_ctl(const char *, const char *, const char *, const char *); #endif -extern int debug; +char securenets_path[MAXPATHLEN]; +enum yp_snf_format securenets_format = YP_SNF_NATIVE; - /* NIS v1 */ const char *yp_procs[] = { + /* NIS v1 */ "ypoldproc_null", "ypoldproc_domain", "ypoldproc_domain_nonack", @@ -87,89 +92,431 @@ const char *yp_procs[] = { "ypproc_maplist" }; +static SLIST_HEAD(, securenet) securenets = + SLIST_HEAD_INITIALIZER(securenets); struct securenet { - struct in_addr net; - struct in_addr mask; - struct securenet *next; + struct sockaddr_storage sn_addr; + struct sockaddr_storage sn_mask; + SLIST_ENTRY(securenet) sn_next; }; -struct securenet *securenets; +static int +mask2prefixlen(const struct sockaddr *sap, int *prefixlen) +{ + switch (sap->sa_family) { +#ifdef AF_INET + case AF_INET: + return (yp_mask2prefixlen_in(sap, prefixlen)); + break; +#endif +#ifdef AF_INET6 + case AF_INET6: + return (yp_mask2prefixlen_in6(sap, prefixlen)); + break; +#endif + default: + break; + } + return (-1); +} -#define LINEBUFSZ 1024 +static int +prefixlen2mask(struct sockaddr *sap, const int *prefixlen) +{ + switch (sap->sa_family) { +#ifdef AF_INET + case AF_INET: + return (yp_prefixlen2mask_in(sap, prefixlen)); + break; +#endif +#ifdef AF_INET6 + case AF_INET6: + return (yp_prefixlen2mask_in6(sap, prefixlen)); + break; +#endif + default: + break; + } + return (-1); +} + +void +yp_debug_sa(const struct sockaddr *sap) +{ + int error; + int plen; + char host[NI_MAXHOST + 1]; + char serv[NI_MAXSERV + 1]; + + error = getnameinfo(sap, sap->sa_len, host, sizeof(host), serv, + sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV); + if (error) + yp_error("sockaddr: %s", gai_strerror(error)); + mask2prefixlen(sap, &plen); + yp_error("sockaddr: %d:[%s]:%s(/%d)", + sap->sa_family, host, serv, plen); +} + +void +show_securenets(void) +{ + struct securenet *snp; + struct sockaddr *sap; + int i = 0; + + yp_error("--- securenets dump start ---"); + SLIST_FOREACH(snp, &securenets, sn_next) { + i++; + yp_error("entry %d:", i); + sap = (struct sockaddr *)&(snp->sn_addr); + yp_debug_sa(sap); + sap = (struct sockaddr *)&(snp->sn_mask); + yp_debug_sa(sap); + } + yp_error("--- securenets dump end ---"); +} /* * Read /var/yp/securenets file and initialize the securenets * list. If the file doesn't exist, we set up a dummy entry that * allows all hosts to connect. */ -void +#define YP_ACL_HOSTMASK_INET "255.255.255.255" +#define YP_ACL_HOSTMASK_INET6 "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" +int load_securenets(void) { FILE *fp; - char path[MAXPATHLEN + 2]; - char linebuf[1024 + 2]; - struct securenet *tmp; - - /* - * If securenets is not NULL, we are being called to reload - * the list; free the existing list before re-reading the - * securenets file. - */ - while (securenets) { - tmp = securenets->next; - free(securenets); - securenets = tmp; + char linebuf[BUFSIZ + 2]; + struct securenet *snp; + struct sockaddr *sap; + int error = 0; + int line; + struct addrinfo hints, *res, *res0; + + if (SLIST_EMPTY(&securenets)) + SLIST_INIT(&securenets); + else { + /* + * If securenets is not NULL, we are being called to reload + * the list; free the existing list before re-reading the + * securenets file. + */ + while (!SLIST_EMPTY(&securenets)) { + snp = SLIST_FIRST(&securenets); + SLIST_REMOVE_HEAD(&securenets, sn_next); + free(snp); + } } - - snprintf(path, MAXPATHLEN, "%s/securenets", yp_dir); - - if ((fp = fopen(path, "r")) == NULL) { + if (debug) + yp_error("load_securenets(): loading %s", securenets_path); + if ((fp = fopen(securenets_path, "r")) == NULL) { if (errno == ENOENT) { - securenets = (struct securenet *)malloc(sizeof(struct securenet)); - securenets->net.s_addr = INADDR_ANY; - securenets->mask.s_addr = INADDR_ANY; - securenets->next = NULL; - return; + /* Create empty access list. */ + if (debug) + yp_error("load_securenets(): ENOENT"); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_flags = AI_PASSIVE; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(NULL, "0", &hints, &res0); + if (error) { + yp_error("getaddrinfo() failed: %s", + gai_strerror(error)); + freeaddrinfo(res0); + return (1); + } + for (res = res0; res; res = res->ai_next) { + snp = malloc(sizeof(*snp)); + if (snp == NULL) { + yp_error("malloc failed: %s", + strerror(errno)); + freeaddrinfo(res0); + return (1); + } + memset(snp, 0, sizeof(*snp)); + memcpy(&snp->sn_addr, res->ai_addr, + sizeof(res->ai_addrlen)); + memcpy(&snp->sn_mask, res->ai_addr, + sizeof(res->ai_addrlen)); + sap = (struct sockaddr *)&(snp->sn_mask); + prefixlen2mask(sap, 0); + SLIST_INSERT_HEAD(&securenets, snp, sn_next); + } + freeaddrinfo(res0); + return (0); } else { - yp_error("fopen(%s) failed: %s", path, strerror(errno)); - exit(1); + yp_error("fopen(%s) failed: %s", securenets_path, + strerror(errno)); + return (1); } } - securenets = NULL; - - while (fgets(linebuf, LINEBUFSZ, fp)) { - char addr1[20], addr2[20]; - + line = 0; + while (fgets(linebuf, sizeof(linebuf), fp)) { + int nitems; + const char *col_host; + const char *col_mask; + char addr1[NI_MAXHOST + 1]; + char addr2[NI_MAXHOST + 1]; + int plen; + sa_family_t family; + char *p; + + line++; + if (debug) + yp_error("load_securenets(): read line %d", line); if ((linebuf[0] == '#') || (strspn(linebuf, " \t\r\n") == strlen(linebuf))) continue; - if (sscanf(linebuf, "%s %s", addr1, addr2) < 2) { - yp_error("badly formatted securenets entry: %s", - linebuf); + nitems = sscanf(linebuf, "%s %s", addr1, addr2); + snp = malloc(sizeof(*snp)); + memset(snp, 0, sizeof(*snp)); + + if (debug) + yp_error("load_securenets(): nitems = %d", nitems); + if (nitems == 2) { + switch (securenets_format) { + case YP_SNF_NATIVE: + /* ex. 127.0.0.1 255.0.0.0 */ + col_host = addr1; + col_mask = addr2; + break; + case YP_SNF_SOLARIS: + /* ex. 255.0.0.0 127.0.0.1 */ + col_host = addr2; + col_mask = addr1; + break; + default: + yp_error("line %d: internal error: %s", + line, linebuf); + continue; + + } + if (debug) { + yp_error("load_securenets(): try mask expr"); + yp_error("load_securenets(): host = [%s]", + col_host); + yp_error("load_securenets(): mask = [%s]", + col_mask); + } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(col_host, NULL, &hints, &res0); + if (error) { + yp_error("line %d: " + "badly formatted securenets entry: " + "%s: %s", line, linebuf, + gai_strerror(error)); + freeaddrinfo(res0); + free(snp); + continue; + } + memcpy(&snp->sn_addr, res0->ai_addr, res0->ai_addrlen); + family = res0->ai_addr->sa_family; + freeaddrinfo(res0); + + if ((securenets_format == YP_SNF_SOLARIS) && + (strcmp(col_host, "host") == 0)) { + switch (family) { +#ifdef AF_INET + case AF_INET: + col_host = YP_ACL_HOSTMASK_INET; + break; +#endif +#ifdef AF_INET6 + case AF_INET6: + col_host = YP_ACL_HOSTMASK_INET6; + break; +#endif + default: + yp_error("line %d: host keyword for " + "unsupported address family: " + "%s: %s", line, linebuf, + gai_strerror(error)); + continue; + } + } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(col_mask, NULL, &hints, &res0); + if (error) { + yp_error("line %d: " + "badly formatted securenets entry: " + "%s: %s", line, linebuf, + gai_strerror(error)); + freeaddrinfo(res0); + free(snp); + continue; + } + memcpy(&snp->sn_mask, res0->ai_addr, res0->ai_addrlen); + freeaddrinfo(res0); + } else if (nitems == 1) { + /* ex. 127.0.0.1/8 */ + /* ex. fe80::/10 */ + if (debug) + yp_error("load_securenets(): try CIDR expr"); + p = strrchr(addr1, '/'); + if (p != NULL) { + *p = ' '; + nitems = sscanf(addr1, "%s %d", addr2, &plen); + if (nitems < 2) { + yp_error("line %d: " + "badly formatted securenets entry:" + " %s", line, linebuf); + free(snp); + continue; + } + } else + memcpy(addr2, addr1, sizeof(addr2)); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(addr2, NULL, &hints, &res0); + if (error) { + yp_error("line %d: " + "badly formatted securenets entry: " + "%s: %s", line, linebuf, + gai_strerror(error)); + freeaddrinfo(res0); + free(snp); + continue; + } + if (p == NULL) + switch (res0->ai_addr->sa_family) { +#ifdef AF_INET + case AF_INET: + plen = 32; + break; +#endif +#ifdef AF_INET6 + case AF_INET6: + plen = 128; + break; +#endif + default: + yp_error("line %d: " + "unsupported address family: " + "%s: %s", line, linebuf, + gai_strerror(error)); + continue; + } + if (debug) { + yp_error("load_securenets(): addr2 = [%s]", + addr2); + yp_error("load_securenets(): plen = [%d]", + plen); + } + memcpy(&snp->sn_addr, res0->ai_addr, res0->ai_addrlen); + memcpy(&snp->sn_mask, res0->ai_addr, res0->ai_addrlen); + freeaddrinfo(res0); + + sap = (struct sockaddr *)&(snp->sn_mask); + prefixlen2mask(sap, &plen); + } else { + yp_error("line %d: " + "badly formatted securenets entry: " + "%s", line, linebuf); continue; } - - tmp = (struct securenet *)malloc(sizeof(struct securenet)); - - if (!inet_aton((char *)&addr1, (struct in_addr *)&tmp->net)) { - yp_error("badly formatted securenets entry: %s", addr1); - free(tmp); - continue; + if (debug) { + yp_error("load_securenets(): adding entry"); + yp_debug_sa((struct sockaddr*)&(snp->sn_addr)); + yp_debug_sa((struct sockaddr *)&(snp->sn_mask)); } - - if (!inet_aton((char *)&addr2, (struct in_addr *)&tmp->mask)) { - yp_error("badly formatted securenets entry: %s", addr2); - free(tmp); - continue; - } - - tmp->next = securenets; - securenets = tmp; + SLIST_INSERT_HEAD(&securenets, snp, sn_next); } - fclose(fp); + if (debug) + show_securenets(); + return (0); +} +static int +compare_subnet(struct sockaddr *addr1, + struct sockaddr *addr2, + struct sockaddr *mask) +{ +#ifdef AF_INET + struct sockaddr_in *in_addr1; + struct sockaddr_in *in_addr2; + struct sockaddr_in *in_addrm; +#endif +#ifdef AF_INET6 + struct sockaddr_in6 *in6_addr1; + struct sockaddr_in6 *in6_addr2; + struct sockaddr_in6 *in6_addrm; +#endif + u_char a1[sizeof(struct sockaddr_storage)]; + u_char a2[sizeof(struct sockaddr_storage)]; + u_char m[sizeof(struct sockaddr_storage)]; + ssize_t len; + int i; + int samescope; + + if (addr1->sa_family != addr2->sa_family) + return (1); + + memset(a1, 0, sizeof(a1)); + memset(a1, 0, sizeof(a2)); + memset(m, 0, sizeof(m)); + + switch (addr1->sa_family) { +#ifdef AF_INET + case AF_INET: + in_addr1 = (struct sockaddr_in *)(addr1); + in_addr2 = (struct sockaddr_in *)(addr2); + in_addrm = (struct sockaddr_in *)(mask); + len = sizeof(in_addr1->sin_addr.s_addr); + memcpy(a1, (u_char *)&(in_addr1->sin_addr.s_addr), + sizeof(in_addr1->sin_addr.s_addr)); + memcpy(a2, (u_char *)&(in_addr2->sin_addr.s_addr), + sizeof(in_addr2->sin_addr.s_addr)); + memcpy(m, (u_char *)&(in_addrm->sin_addr.s_addr), + sizeof(in_addrm->sin_addr.s_addr)); + samescope = 1; + break; +#endif +#ifdef AF_INET6 + case AF_INET6: + in6_addr1 = (struct sockaddr_in6 *)(addr1); + in6_addr2 = (struct sockaddr_in6 *)(addr2); + in6_addrm = (struct sockaddr_in6 *)(mask); + len = sizeof(in6_addr1->sin6_addr.s6_addr); + memcpy(a1, (u_char *)in6_addr1->sin6_addr.s6_addr, + sizeof(in6_addr1->sin6_addr.s6_addr)); + memcpy(a2, (u_char *)in6_addr2->sin6_addr.s6_addr, + sizeof(in6_addr2->sin6_addr.s6_addr)); + memcpy(m, (u_char *)in6_addrm->sin6_addr.s6_addr, + sizeof(in6_addrm->sin6_addr.s6_addr)); + samescope = (in6_addr1->sin6_scope_id == + in6_addr2->sin6_scope_id); + break; +#endif + default: + return (1); + } + for (i=0; i < len; i++) { + a1[i] &= m[i]; + a2[i] &= m[i]; + } + if (debug) { + yp_error("compare_subnet(): addr1"); + yp_debug_sa(addr1); + yp_error("compare_subnet(): addr2"); + yp_debug_sa(addr2); + yp_error("compare_subnet(): mask"); + yp_debug_sa(mask); + } + if (!samescope) + return (1); + return (memcmp(a1, a2, len)); } /* @@ -211,15 +558,21 @@ int yp_access(const char *map, const struct svc_req *rqstp) #endif { - struct sockaddr_in *rqhost; int status_securenets = 0; + int error; #ifdef TCP_WRAPPER int status_tcpwrap; #endif - static unsigned long oldaddr = 0; - struct securenet *tmp; + static struct sockaddr oldaddr; + struct securenet *snp; + struct sockaddr *sap; + struct netbuf *rqhost; const char *yp_procedure = NULL; char procbuf[50]; + char host[NI_MAXHOST]; + char serv[NI_MAXSERV]; + + memset(&oldaddr, 0, sizeof(oldaddr)); if (rqstp->rq_prog != YPPASSWDPROG && rqstp->rq_prog != YPPROG) { snprintf(procbuf, sizeof(procbuf), "#%lu/#%lu", @@ -232,12 +585,18 @@ yp_access(const char *map, const struct svc_req *rqstp) yp_procs[rqstp->rq_proc + (12 * (rqstp->rq_vers - 1))]; } - rqhost = svc_getcaller(rqstp->rq_xprt); - + rqhost = svc_getrpccaller(rqstp->rq_xprt); + sap = (struct sockaddr *)(rqhost->buf); + error = getnameinfo(sap, sap->sa_len, + host, sizeof(host), serv, sizeof(serv), + NI_NUMERICHOST | NI_NUMERICSERV); + if (error) { + yp_error("yp_access: getnameinfo(): %s", gai_strerror(error)); + return (1); + } if (debug) { - yp_error("procedure %s called from %s:%d", yp_procedure, - inet_ntoa(rqhost->sin_addr), - ntohs(rqhost->sin_port)); + yp_error("procedure %s called from %s:%s", yp_procedure, + host, serv); if (map != NULL) yp_error("client is referencing map \"%s\".", map); } @@ -245,14 +604,13 @@ yp_access(const char *map, const struct svc_req *rqstp) /* Check the map name if one was supplied. */ if (map != NULL) { if (strchr(map, '/')) { - yp_error("embedded slash in map name \"%s\" -- \ -possible spoof attempt from %s:%d", - map, inet_ntoa(rqhost->sin_addr), - ntohs(rqhost->sin_port)); - return(1); + yp_error("embedded slash in map name \"%s\" " + "-- possible spoof attempt from %s:%s", + map, host, serv); + return (1); } #ifdef DB_CACHE - if ((yp_testflag((char *)map, (char *)domain, YP_SECURE) || + if ((yp_testflag((const char *)map, (const char *)domain, YP_SECURE) || #else if ((strstr(map, "master.passwd.") || strstr(map, "shadow.") || #endif @@ -260,27 +618,30 @@ possible spoof attempt from %s:%d", rqstp->rq_proc == YPPROC_XFR) || (rqstp->rq_prog == YPXFRD_FREEBSD_PROG && rqstp->rq_proc == YPXFRD_GETMAP)) && - ntohs(rqhost->sin_port) >= IPPORT_RESERVED) { - yp_error("access to %s denied -- client %s:%d \ -not privileged", map, inet_ntoa(rqhost->sin_addr), ntohs(rqhost->sin_port)); - return(1); + atoi(serv) >= IPPORT_RESERVED) { + yp_error("access to %s denied -- client %s:%s" + " not privileged", map, host, serv); + return (1); } } #ifdef TCP_WRAPPER - status_tcpwrap = hosts_ctl("ypserv", STRING_UNKNOWN, - inet_ntoa(rqhost->sin_addr), ""); + status_tcpwrap = hosts_ctl("ypserv", STRING_UNKNOWN, host, ""); #endif - tmp = securenets; - while (tmp) { - if (((rqhost->sin_addr.s_addr & ~tmp->mask.s_addr) - | tmp->net.s_addr) == rqhost->sin_addr.s_addr) { + if (debug) + yp_error("yp_access(): compare start"); + SLIST_FOREACH (snp, &securenets, sn_next) { + if (compare_subnet(sap, + (struct sockaddr *)&(snp->sn_addr), + (struct sockaddr *)&(snp->sn_mask)) == 0) { status_securenets = 1; + if (debug) + yp_error("yp_access(): compare success!"); break; } - tmp = tmp->next; } - + if (debug) + yp_error("yp_access(): compare end"); #ifdef TCP_WRAPPER if (status_securenets == 0 || status_tcpwrap == 0) { #else @@ -296,16 +657,14 @@ not privileged", map, inet_ntoa(rqhost->sin_addr), ntohs(rqhost->sin_port)); * * In either case deny access. */ - if (rqhost->sin_addr.s_addr != oldaddr) { - yp_error("connect from %s:%d to procedure %s refused", - inet_ntoa(rqhost->sin_addr), - ntohs(rqhost->sin_port), - yp_procedure); - oldaddr = rqhost->sin_addr.s_addr; + if (memcmp(sap, &oldaddr, sizeof(oldaddr))) { + yp_error("connect from %s:%s to procedure %s refused", + host, serv, yp_procedure); + memcpy(&oldaddr, sap, sizeof(oldaddr)); } - return(1); + return (1); } - return(0); + return (0); } @@ -318,13 +677,12 @@ yp_validdomain(const char *domain) if (domain == NULL || strstr(domain, "binding") || !strcmp(domain, ".") || !strcmp(domain, "..") || strchr(domain, '/') || strlen(domain) > YPMAXDOMAIN) - return(1); + return (1); snprintf(dompath, sizeof(dompath), "%s/%s", yp_dir, domain); if (stat(dompath, &statbuf) < 0 || !S_ISDIR(statbuf.st_mode)) - return(1); - + return (1); - return(0); + return (0); } diff --git a/usr.sbin/ypserv/yp_access_inet.c b/usr.sbin/ypserv/yp_access_inet.c new file mode 100644 index 0000000..c8ff52e --- /dev/null +++ b/usr.sbin/ypserv/yp_access_inet.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2010-2011 Hiroki Sato. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul 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. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <string.h> +#include <stdlib.h> + +#include "yp_extern.h" + +int +yp_mask2prefixlen_in(const struct sockaddr *sap, int *prefixlen) +{ + int x, y = 0; + const u_char *p; + const struct in_addr *addr; + const struct sockaddr_in *sainp; + + sainp = (const struct sockaddr_in *)sap; + addr = &(sainp->sin_addr); + p = (const u_char *)&addr->s_addr; + for (x = 0; x < (int)sizeof(addr->s_addr); x++) + if (p[x] != 0xff) + break; + if (x < (int)sizeof(addr->s_addr)) + for (y = 0; y < 8; y++) + if ((p[x] & (0x80 >> y)) == 0) + break; + *prefixlen = x * 8 + y; + return (0); +} + +int +yp_prefixlen2mask_in(struct sockaddr *sap, const int *prefixlen) +{ + int i; + int len; + u_char *p; + struct in_addr *addr; + struct sockaddr_in *sainp; + + len = *prefixlen; + if (0 > len || len > 32) + return (-1); + + sainp = (struct sockaddr_in *)sap; + memset(&sainp->sin_addr, 0, sizeof(sainp->sin_addr)); + addr = &(sainp->sin_addr); + p = (u_char *)&addr->s_addr; + for (i = 0; i < len / 8; i++) + p[i] = 0xff; + if (len % 8) + p[i] = (0xff00 >> (len % 8)) & 0xff; + return (0); +} + +struct sockaddr * +yp_mask_in(const struct sockaddr *addr, const struct sockaddr *mask) +{ + int i; + const u_char *p, *q; + u_char *r; + const struct sockaddr_in *in_addr; + const struct sockaddr_in *in_mask; + struct sockaddr_in *in_res; + + in_addr = (const struct sockaddr_in *)addr; + in_mask = (const struct sockaddr_in *)mask; + + if ((in_res = malloc(sizeof(*in_res))) == NULL) + return NULL; + memcpy(in_res, in_addr, sizeof(*in_res)); + p = (const u_char *)&(in_addr->sin_addr.s_addr); + q = (const u_char *)&(in_mask->sin_addr.s_addr); + r = (u_char *)&(in_res->sin_addr.s_addr); + for (i = 0; i < (int)sizeof(in_addr->sin_addr.s_addr); i++) + r[i] = p[i] & q[i]; + + return ((struct sockaddr *)in_res); +} + +int +yp_compare_subnet_in(const struct sockaddr *a1, const struct sockaddr *a2) +{ + const struct sockaddr_in *in_a1 = (const struct sockaddr_in *)a1; + const struct sockaddr_in *in_a2 = (const struct sockaddr_in *)a2; + + if (debug) { + yp_error("yp_subnet_cmp_in(): a1"); + yp_debug_sa(a1); + yp_error("yp_subnet_cmp_in(): a2"); + yp_debug_sa(a2); + } + return (memcmp((const u_char *)&(in_a1->sin_addr.s_addr), + (const u_char *)&(in_a2->sin_addr.s_addr), + sizeof(in_a1->sin_addr.s_addr))); +} diff --git a/usr.sbin/ypserv/yp_access_inet6.c b/usr.sbin/ypserv/yp_access_inet6.c new file mode 100644 index 0000000..a45de20 --- /dev/null +++ b/usr.sbin/ypserv/yp_access_inet6.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2010-2011 Hiroki Sato. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul 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. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <stdlib.h> +#include <string.h> + +#include "yp_extern.h" + +int +yp_mask2prefixlen_in6(const struct sockaddr *sap, int *prefixlen) +{ + int x, y = 0; + const u_char *p; + const struct in6_addr *addr; + const struct sockaddr_in6 *sain6p; + + sain6p = (const struct sockaddr_in6 *)sap; + addr = &(sain6p->sin6_addr); + for (x = 0; x < (int)sizeof(addr->s6_addr); x++) + if (addr->s6_addr[x] != 0xff) + break; + if (x < (int)sizeof(addr->s6_addr)) + for (y = 0; y < 8; y++) + if ((addr->s6_addr[x] & (0x80 >> y)) == 0) + break; + if (x < (int)sizeof(addr->s6_addr)) { + if (y != 0 && (addr->s6_addr[x] & (0x00ff >> y)) != 0) + return (-1); + p = (const u_char *)&addr->s6_addr[x + 1]; + for (; p < addr->s6_addr + sizeof(addr->s6_addr); p++) + if (*p != 0) + return (-1); + } + *prefixlen = x * 8 + y; + return (0); +} + +int +yp_prefixlen2mask_in6(struct sockaddr *sap, const int *prefixlen) +{ + int i; + int len; + int bytelen, bitlen; + u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; + struct in6_addr *addr; + struct sockaddr_in6 *sain6p; + + len = *prefixlen; + if (0 > len || len > 128) + return (-1); + + sain6p = (struct sockaddr_in6 *)sap; + memset(&sain6p->sin6_addr, 0, sizeof(sain6p->sin6_addr)); + addr = &(sain6p->sin6_addr); + bytelen = len / 8; + bitlen = len % 8; + for (i = 0; i < bytelen; i++) + addr->s6_addr[i] = 0xff; + if (bitlen) + addr->s6_addr[bytelen] = maskarray[bitlen - 1]; + return (0); +} + +struct sockaddr * +yp_mask_in6(const struct sockaddr *addr, const struct sockaddr *mask) +{ + int i; + const u_char *p, *q; + u_char *r; + const struct sockaddr_in6 *in6_addr; + const struct sockaddr_in6 *in6_mask; + struct sockaddr_in6 *in6_res; + + in6_addr = (const struct sockaddr_in6 *)addr; + in6_mask = (const struct sockaddr_in6 *)mask; + + if ((in6_res = malloc(sizeof(*in6_res))) == NULL) + return NULL; + memcpy(in6_res, in6_addr, sizeof(*in6_res)); + p = (const u_char *)&(in6_addr->sin6_addr.s6_addr); + q = (const u_char *)&(in6_mask->sin6_addr.s6_addr); + r = (u_char *)&(in6_res->sin6_addr.s6_addr); + for (i = 0; i < (int)sizeof(in6_addr->sin6_addr.s6_addr); i++) + r[i] = p[i] & q[i]; + + return ((struct sockaddr *)in6_res); +} + +int +yp_compare_subnet_in6(const struct sockaddr *a1, const struct sockaddr *a2) +{ + const struct sockaddr_in6 *in6_a1 = (const struct sockaddr_in6 *)a1; + const struct sockaddr_in6 *in6_a2 = (const struct sockaddr_in6 *)a2; + + if (debug) { + yp_error("yp_subnet_cmp_in6(): a1"); + yp_debug_sa(a1); + yp_error("yp_subnet_cmp_in6(): a2"); + yp_debug_sa(a2); + yp_error("yp_subnet_cmp_in6(): scope: %d - %d", + in6_a1->sin6_scope_id, in6_a2->sin6_scope_id); + } + + if (in6_a1->sin6_scope_id != in6_a2->sin6_scope_id) + return (-1); + + return (memcmp(in6_a1->sin6_addr.s6_addr, + in6_a2->sin6_addr.s6_addr, + sizeof(in6_a1->sin6_addr.s6_addr))); +} diff --git a/usr.sbin/ypserv/yp_dblookup.c b/usr.sbin/ypserv/yp_dblookup.c index 61944dc..5dfc637 100644 --- a/usr.sbin/ypserv/yp_dblookup.c +++ b/usr.sbin/ypserv/yp_dblookup.c @@ -67,6 +67,7 @@ HASHINFO openinfo = { #define MAXDBS 20 #endif +static char nullbuf[] = ""; static int numdbs = 0; struct dbent { @@ -193,10 +194,8 @@ yp_flush_all(void) return; } -static char *inter_string = "YP_INTERDOMAIN"; -static char *secure_string = "YP_SECURE"; -static int inter_sz = sizeof("YP_INTERDOMAIN") - 1; -static int secure_sz = sizeof("YP_SECURE") - 1; +static char inter_string[] = "YP_INTERDOMAIN"; +static char secure_string[] = "YP_SECURE"; static int yp_setflags(DB *dbp) @@ -205,13 +204,13 @@ yp_setflags(DB *dbp) int flags = 0; key.data = inter_string; - key.size = inter_sz; + key.size = sizeof(inter_string) - 1; if (!(dbp->get)(dbp, &key, &data, 0)) flags |= YP_INTERDOMAIN; key.data = secure_string; - key.size = secure_sz; + key.size = sizeof(secure_string) - 1; if (!(dbp->get)(dbp, &key, &data, 0)) flags |= YP_SECURE; @@ -220,7 +219,7 @@ yp_setflags(DB *dbp) } int -yp_testflag(char *map, char *domain, int flag) +yp_testflag(const char *map, const char *domain, int flag) { char buf[MAXPATHLEN + 2]; register struct circleq_entry *qptr; @@ -501,7 +500,7 @@ yp_get_record(const char *domain, const char *map, #ifdef DB_CACHE if (TAILQ_FIRST(&qhead)->dbptr->size) { - TAILQ_FIRST(&qhead)->dbptr->key = ""; + TAILQ_FIRST(&qhead)->dbptr->key = nullbuf; TAILQ_FIRST(&qhead)->dbptr->size = 0; } #else diff --git a/usr.sbin/ypserv/yp_dnslookup.c b/usr.sbin/ypserv/yp_dnslookup.c index 4ea6a13..c18e220 100644 --- a/usr.sbin/ypserv/yp_dnslookup.c +++ b/usr.sbin/ypserv/yp_dnslookup.c @@ -223,7 +223,7 @@ yp_send_dns_reply(struct circleq_dnsentry *q, char *buf) { ypresponse result_v1; ypresp_val result_v2; - unsigned long xid; + unsigned long xid = 0; struct sockaddr_in client_addr; xdrproc_t xdrfunc; char *result; @@ -456,7 +456,7 @@ yp_async_lookup_name(struct svc_req *rqstp, char *name, int af) pending++; if (debug) - yp_error("queueing async DNS name lookup (%d)", q->id); + yp_error("queueing async DNS name lookup (%lu)", q->id); yp_prune_dnsq(); return(YP_TRUE); @@ -544,7 +544,7 @@ yp_async_lookup_addr(struct svc_req *rqstp, char *addr, int af) pending++; if (debug) - yp_error("queueing async DNS address lookup (%d)", q->id); + yp_error("queueing async DNS address lookup (%lu)", q->id); yp_prune_dnsq(); return(YP_TRUE); diff --git a/usr.sbin/ypserv/yp_error.c b/usr.sbin/ypserv/yp_error.c index 8d488f3..d3589c7 100644 --- a/usr.sbin/ypserv/yp_error.c +++ b/usr.sbin/ypserv/yp_error.c @@ -48,8 +48,6 @@ __FBSDID("$FreeBSD$"); int debug; extern int _rpcpmstart; -extern char *progname; - static void __verr(const char *fmt, va_list ap) __printflike(1, 0); static void __verr(const char *fmt, va_list ap) diff --git a/usr.sbin/ypserv/yp_extern.h b/usr.sbin/ypserv/yp_extern.h index 2e574b6..bb7d8af 100644 --- a/usr.sbin/ypserv/yp_extern.h +++ b/usr.sbin/ypserv/yp_extern.h @@ -32,15 +32,16 @@ * $FreeBSD$ */ +#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/types.h> +#include <rpc/rpc.h> +#include <rpcsvc/yp.h> #include <db.h> #include <limits.h> #include <stdio.h> #include <string.h> #include <unistd.h> -#include <sys/cdefs.h> -#include <sys/types.h> -#include <rpc/rpc.h> -#include <rpcsvc/yp.h> #ifndef _PATH_YP #define _PATH_YP "/var/yp/" @@ -57,6 +58,8 @@ #define YP_SECURE 0x1 #define YP_INTERDOMAIN 0x2 +#define SECURENETS_FNAME "securenets" + /* * External functions and variables. */ @@ -66,9 +69,13 @@ extern int ypdb_debug; extern int do_dns; extern int children; extern int resfd; -extern char *progname; -extern char *yp_dir; +extern const char *progname; +extern const char *yp_dir; extern pid_t yp_pid; +extern char securenets_path[MAXPATHLEN]; +extern enum yp_snf_format { + YP_SNF_NATIVE, + YP_SNF_SOLARIS } securenets_format; extern enum ypstat yp_errno; extern void yp_error(const char *, ...) __printflike(1, 2); @@ -86,13 +93,27 @@ extern int yp_access(const char *, const char *, const struct svc_req *); #else extern int yp_access(const char *, const struct svc_req *); #endif +extern void yp_debug_sa(const struct sockaddr *); +#ifdef AF_INET +extern int yp_mask2prefixlen_in(const struct sockaddr *, int *); +extern int yp_prefixlen2mask_in(struct sockaddr *, const int *); +extern struct sockaddr *yp_mask_in(const struct sockaddr *, const struct sockaddr *); +extern int yp_compare_subnet_in(const struct sockaddr *, const struct sockaddr *); +#endif +#ifdef AF_INET6 +extern int yp_mask2prefixlen_in6(const struct sockaddr *, int *); +extern int yp_prefixlen2mask_in6(struct sockaddr *, const int *); +extern struct sockaddr *yp_mask_in6(const struct sockaddr *, const struct sockaddr *); +extern int yp_compare_subnet_in6(const struct sockaddr *, const struct sockaddr *); +#endif extern int yp_validdomain(const char *); extern DB *yp_open_db(const char *, const char *); extern DB *yp_open_db_cache(const char *, const char *, const char *, int); extern void yp_flush_all(void); extern void yp_init_dbs(void); -extern int yp_testflag(char *, char *, int); -extern void load_securenets(void); +extern int yp_testflag(const char *, const char *, int); +extern int load_securenets(void); +extern void show_securenets(void); #ifdef DB_CACHE extern ypstat yp_select_map(char *, char *, keydat *, int); diff --git a/usr.sbin/ypserv/yp_main.c b/usr.sbin/ypserv/yp_main.c index ec39d1b..71bc905 100644 --- a/usr.sbin/ypserv/yp_main.c +++ b/usr.sbin/ypserv/yp_main.c @@ -44,7 +44,8 @@ __FBSDID("$FreeBSD$"); #include <sys/queue.h> #include <sys/socket.h> #include <sys/wait.h> -#include "yp.h" +#include <rpc/rpc.h> +#include <rpc/rpc_com.h> #include <err.h> #include <errno.h> #include <memory.h> @@ -59,58 +60,58 @@ __FBSDID("$FreeBSD$"); #include <sysent.h> /* getdtablesize, open */ #endif /* __cplusplus */ #include <netinet/in.h> +#include <netconfig.h> #include <netdb.h> + +#include "yp.h" #include "yp_extern.h" -#include <netconfig.h> -#include <rpc/rpc.h> -#include <rpc/rpc_com.h> #ifndef SIG_PF #define SIG_PF void(*)(int) #endif #define _RPCSVC_CLOSEDOWN 120 -int _rpcpmstart; /* Started by a port monitor ? */ -static int _rpcfdtype; - /* Whether Stream or Datagram ? */ +int _rpcpmstart; /* Started by a port monitor ? */ +static int _rpcfdtype; /* Whether Stream or Datagram ? */ static int _rpcaf; static int _rpcfd; - /* States a server can be in wrt request */ +/* States a server can be in wrt request */ +/* Set when a request is serviced */ +static enum rpcsvcstate { + _IDLE = 0, + _SERVED, + _SERVING, +} _rpcsvcstate; -#define _IDLE 0 -#define _SERVED 1 -#define _SERVING 2 +const char *progname = "ypserv"; +const char *yp_dir = _PATH_YP; +static char *servname = NULL; -extern void ypprog_1(struct svc_req *, SVCXPRT *); -extern void ypprog_2(struct svc_req *, SVCXPRT *); -extern int _rpc_dtablesize(void); -extern int _rpcsvcstate; /* Set when a request is serviced */ -char *progname = "ypserv"; -char *yp_dir = _PATH_YP; -/*int debug = 0;*/ int do_dns = 0; int resfd; +int debug; +pid_t yp_pid; struct socklistent { + SLIST_ENTRY(socklistent) sle_next; + int sle_sock; struct sockaddr_storage sle_ss; - SLIST_ENTRY(socklistent) sle_next; }; static SLIST_HEAD(, socklistent) sle_head = SLIST_HEAD_INITIALIZER(sle_head); struct bindaddrlistent { - const char *ble_hostname; SLIST_ENTRY(bindaddrlistent) ble_next; + + const char *ble_hostname; }; static SLIST_HEAD(, bindaddrlistent) ble_head = SLIST_HEAD_INITIALIZER(ble_head); -static char *servname = "0"; - -static -void _msgout(char* msg, ...) +static void +_msgout(const char* msg, ...) { va_list ap; @@ -125,8 +126,6 @@ void _msgout(char* msg, ...) va_end(ap); } -pid_t yp_pid; - static void yp_svc_run(void) { @@ -188,24 +187,22 @@ unregister(void) static void reaper(int sig) { - int status; - int saved_errno; + int status; + int saved_errno; saved_errno = errno; - - if (sig == SIGHUP) { + switch (sig) { + case SIGHUP: load_securenets(); #ifdef DB_CACHE yp_flush_all(); #endif - errno = saved_errno; - return; - } - - if (sig == SIGCHLD) { + break; + case SIGCHLD: while (wait3(&status, WNOHANG, NULL) > 0) children--; - } else { + break; + default: unregister(); exit(0); } @@ -216,15 +213,16 @@ reaper(int sig) static void usage(void) { - fprintf(stderr, "usage: ypserv [-h] [-d] [-n] [-p path] [-P port]\n"); - exit(1); + fprintf(stderr, "usage: ypserv " + "[-d] [-h hostname] [-n] [-p ypdir] [-P port] [-S]\n"); } static void closedown(int sig) { + if (sig != SIGALRM) + return; if (_rpcsvcstate == _IDLE) { - extern fd_set svc_fdset; static int size; int i, openfd; @@ -246,8 +244,8 @@ closedown(int sig) if (_rpcsvcstate == _SERVED) _rpcsvcstate = _IDLE; - (void) signal(SIGALRM, (SIG_PF) closedown); - (void) alarm(_RPCSVC_CLOSEDOWN/2); + (void)signal(SIGALRM, (SIG_PF)closedown); + (void)alarm(_RPCSVC_CLOSEDOWN/2); } static int @@ -261,10 +259,13 @@ create_service(const int sock, const struct netconfig *nconf, struct socklistent *slep; struct bindaddrlistent *blep; struct netbuf svcaddr; + char nullserv[] = "0"; SLIST_INIT(&sle_head); memset(&hints, 0, sizeof(hints)); memset(&svcaddr, 0, sizeof(svcaddr)); + if (servname == NULL) + servname = nullserv; hints.ai_family = si->si_af; hints.ai_socktype = si->si_socktype; @@ -282,9 +283,10 @@ create_service(const int sock, const struct netconfig *nconf, error = getaddrinfo(blep->ble_hostname, servname, &hints, &res0); if (error) { - _msgout("getaddrinfo(): %s", - gai_strerror(error)); - return -1; + _msgout("%s: getaddrinfo(): %s", + __func__, + gai_strerror(error)); + return (-1); } for (res = res0; res; res = res->ai_next) { int s; @@ -301,7 +303,7 @@ create_service(const int sock, const struct netconfig *nconf, nconf->nc_netid, strerror(errno)); freeaddrinfo(res0); - return -1; + return (-1); } if (bindresvport_sa(s, res->ai_addr) == -1) { if ((errno != EPERM) || @@ -313,7 +315,7 @@ create_service(const int sock, const struct netconfig *nconf, strerror(errno)); freeaddrinfo(res0); close(sock); - return -1; + return (-1); } } if (nconf->nc_semantics != NC_TPI_CLTS) @@ -325,7 +327,7 @@ create_service(const int sock, const struct netconfig *nconf, strerror(errno)); freeaddrinfo(res0); close(s); - return -1; + return (-1); } memset(slep, 0, sizeof(*slep)); memcpy(&slep->sle_ss, @@ -338,7 +340,8 @@ create_service(const int sock, const struct netconfig *nconf, * If servname == "0", redefine it by using * the bound socket. */ - if (strncmp("0", servname, 1) == 0) { + if (servname == NULL || + strncmp("0", servname, 1) == 0) { struct sockaddr *sap; socklen_t slen; char *sname; @@ -349,30 +352,30 @@ create_service(const int sock, const struct netconfig *nconf, strerror(errno)); freeaddrinfo(res0); close(s); - return -1; + return (-1); } memset(sname, 0, NI_MAXSERV); sap = (struct sockaddr *)&slep->sle_ss; - slen = sizeof(*sap); + slen = sap->sa_len; error = getsockname(s, sap, &slen); if (error) { _msgout("getsockname(): %s", strerror(errno)); freeaddrinfo(res0); close(s); - return -1; + return (-1); } - error = getnameinfo(sap, slen, + error = getnameinfo(sap, sap->sa_len, NULL, 0, sname, NI_MAXSERV, - NI_NUMERICHOST | NI_NUMERICSERV); + NI_NUMERICSERV); if (error) { _msgout("getnameinfo(): %s", - strerror(errno)); + gai_strerror(error)); freeaddrinfo(res0); close(s); - return -1; + return (-1); } servname = sname; } @@ -383,7 +386,7 @@ create_service(const int sock, const struct netconfig *nconf, slep = malloc(sizeof(*slep)); if (slep == NULL) { _msgout("malloc failed: %s", strerror(errno)); - return -1; + return (-1); } memset(slep, 0, sizeof(*slep)); slep->sle_sock = sock; @@ -419,9 +422,11 @@ create_service(const int sock, const struct netconfig *nconf, continue; } } - while(!(SLIST_EMPTY(&sle_head))) + while(!(SLIST_EMPTY(&sle_head))) { + slep = SLIST_FIRST(&sle_head); SLIST_REMOVE_HEAD(&sle_head, sle_next); - + free(slep); + } /* * Register RPC service to rpcbind by using AI_PASSIVE address. */ @@ -429,7 +434,7 @@ create_service(const int sock, const struct netconfig *nconf, error = getaddrinfo(NULL, servname, &hints, &res0); if (error) { _msgout("getaddrinfo(): %s", gai_strerror(error)); - return -1; + return (-1); } svcaddr.buf = res0->ai_addr; svcaddr.len = res0->ai_addrlen; @@ -442,7 +447,7 @@ create_service(const int sock, const struct netconfig *nconf, rpcb_set(YPPROG, YPVERS, nconf, &svcaddr); freeaddrinfo(res0); - return 0; + return (0); } int @@ -460,7 +465,7 @@ main(int argc, char *argv[]) memset(&si, 0, sizeof(si)); SLIST_INIT(&ble_head); - while ((ch = getopt(argc, argv, "dh:np:P:")) != -1) { + while ((ch = getopt(argc, argv, "dh:np:P:S")) != -1) { switch (ch) { case 'd': debug = ypdb_debug = 1; @@ -481,8 +486,12 @@ main(int argc, char *argv[]) case 'P': servname = optarg; break; + case 'S': + securenets_format = YP_SNF_SOLARIS; + break; default: usage(); + exit(1); } } /* @@ -495,6 +504,8 @@ main(int argc, char *argv[]) memset(blep, 0, sizeof(*blep)); SLIST_INSERT_HEAD(&ble_head, blep, ble_next); } + snprintf(securenets_path, sizeof(securenets_path), + "%s/%s", yp_dir, SECURENETS_FNAME); load_securenets(); yp_init_resolver(); @@ -514,13 +525,12 @@ main(int argc, char *argv[]) } else { /* standalone mode */ if (!debug) { - if (daemon(0,0)) { + if (daemon(0,0)) err(1,"cannot fork"); - } openlog("ypserv", LOG_PID, LOG_DAEMON); } _rpcpmstart = 0; - _rpcaf = AF_INET; + _rpcaf = 0; _rpcfd = RPC_ANYFD; unregister(); } @@ -536,12 +546,10 @@ main(int argc, char *argv[]) "Ignored.", nconf->nc_netid); continue; } - if (_rpcpmstart) { + if (_rpcpmstart) if (si.si_socktype != _rpcfdtype || si.si_af != _rpcaf) continue; - } else if (si.si_af != _rpcaf) - continue; error = create_service(_rpcfd, nconf, &si); if (error) { endnetconfig(nc_handle); @@ -551,27 +559,31 @@ main(int argc, char *argv[]) } } endnetconfig(nc_handle); - while(!(SLIST_EMPTY(&ble_head))) + while(!(SLIST_EMPTY(&ble_head))) { + blep = SLIST_FIRST(&ble_head); SLIST_REMOVE_HEAD(&ble_head, ble_next); + free(blep); + } if (ntrans == 0) { _msgout("no transport is available. Aborted."); exit(1); } if (_rpcpmstart) { - (void) signal(SIGALRM, (SIG_PF) closedown); - (void) alarm(_RPCSVC_CLOSEDOWN/2); + (void)signal(SIGALRM, (SIG_PF)closedown); + (void)alarm(_RPCSVC_CLOSEDOWN/2); } /* * Make sure SIGPIPE doesn't blow us away while servicing TCP * connections. */ - (void) signal(SIGPIPE, SIG_IGN); - (void) signal(SIGCHLD, (SIG_PF) reaper); - (void) signal(SIGTERM, (SIG_PF) reaper); - (void) signal(SIGINT, (SIG_PF) reaper); - (void) signal(SIGHUP, (SIG_PF) reaper); + (void)signal(SIGPIPE, SIG_IGN); + (void)signal(SIGCHLD, (SIG_PF)reaper); + (void)signal(SIGTERM, (SIG_PF)reaper); + (void)signal(SIGINT, (SIG_PF)reaper); + (void)signal(SIGHUP, (SIG_PF)reaper); yp_svc_run(); - _msgout("svc_run returned"); - exit(1); + /* NOTREACHED */ + _msgout("svc_run returned"); + return (1); } diff --git a/usr.sbin/ypserv/yp_server.c b/usr.sbin/ypserv/yp_server.c index ba20c3cd..4526a4b 100644 --- a/usr.sbin/ypserv/yp_server.c +++ b/usr.sbin/ypserv/yp_server.c @@ -48,11 +48,10 @@ __FBSDID("$FreeBSD$"); #include <rpc/rpc.h> int children = 0; +static char nullbuf[] = ""; #define MASTER_STRING "YP_MASTER_NAME" -#define MASTER_SZ sizeof(MASTER_STRING) - 1 #define ORDER_STRING "YP_LAST_MODIFIED" -#define ORDER_SZ sizeof(ORDER_STRING) - 1 static pid_t yp_fork(void) @@ -76,6 +75,7 @@ ypproc_null_2_svc(void *argp, struct svc_req *rqstp) static char * result; static char rval = 0; + argp = NULL; #ifdef DB_CACHE if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) #else @@ -135,7 +135,7 @@ ypproc_match_2_svc(ypreq_key *argp, struct svc_req *rqstp) { static ypresp_val result; - result.val.valdat_val = ""; + result.val.valdat_val = nullbuf; result.val.valdat_len = 0; #ifdef DB_CACHE @@ -205,7 +205,7 @@ ypproc_first_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_key_val result; - result.val.valdat_val = result.key.keydat_val = ""; + result.val.valdat_val = result.key.keydat_val = nullbuf; result.val.valdat_len = result.key.keydat_len = 0; #ifdef DB_CACHE @@ -237,7 +237,7 @@ ypproc_next_2_svc(ypreq_key *argp, struct svc_req *rqstp) { static ypresp_key_val result; - result.val.valdat_val = result.key.keydat_val = ""; + result.val.valdat_val = result.key.keydat_val = nullbuf; result.val.valdat_len = result.key.keydat_len = 0; #ifdef DB_CACHE @@ -426,6 +426,7 @@ ypproc_clear_2_svc(void *argp, struct svc_req *rqstp) static char * result; static char rval = 0; + argp = NULL; #ifdef DB_CACHE if (yp_access(NULL, NULL, (struct svc_req *)rqstp)) #else @@ -494,7 +495,7 @@ ypproc_all_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) */ result.more = TRUE; result.ypresp_all_u.val.key.keydat_len = 0; - result.ypresp_all_u.val.key.keydat_val = ""; + result.ypresp_all_u.val.key.keydat_val = nullbuf; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { @@ -574,10 +575,11 @@ ypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_master result; static char ypvalbuf[YPMAXRECORD]; - keydat key = { MASTER_SZ, MASTER_STRING }; + char keybuf[] = MASTER_STRING; + keydat key = { sizeof(keybuf) - 1, keybuf }; valdat val; - result.peer = ""; + result.peer = nullbuf; #ifdef DB_CACHE if (yp_access(argp->map, argp->domain, (struct svc_req *)rqstp)) { @@ -612,7 +614,7 @@ ypproc_master_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) ypvalbuf[val.valdat_len] = '\0'; result.peer = ypvalbuf; } else - result.peer = ""; + result.peer = nullbuf; return (&result); } @@ -621,7 +623,8 @@ ypresp_order * ypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) { static ypresp_order result; - keydat key = { ORDER_SZ, ORDER_STRING }; + char keybuf[] = ORDER_STRING; + keydat key = { sizeof(keybuf) - 1, keybuf }; valdat val; result.ordernum = 0; @@ -662,7 +665,8 @@ ypproc_order_2_svc(ypreq_nokey *argp, struct svc_req *rqstp) return (&result); } -static void yp_maplist_free(struct ypmaplist *yp_maplist) +static void +yp_maplist_free(struct ypmaplist *yp_maplist) { register struct ypmaplist *next; @@ -815,7 +819,7 @@ ypoldproc_match_1_svc(yprequest *argp, struct svc_req *rqstp) ypresp_val *v2_result; result.yp_resptype = YPRESP_VAL; - result.ypresponse_u.yp_resp_valtype.val.valdat_val = ""; + result.ypresponse_u.yp_resp_valtype.val.valdat_val = nullbuf; result.ypresponse_u.yp_resp_valtype.val.valdat_len = 0; if (argp->yp_reqtype != YPREQ_KEY) { @@ -844,7 +848,7 @@ ypoldproc_first_1_svc(yprequest *argp, struct svc_req *rqstp) result.yp_resptype = YPRESP_KEY_VAL; result.ypresponse_u.yp_resp_key_valtype.val.valdat_val = - result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = ""; + result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = nullbuf; result.ypresponse_u.yp_resp_key_valtype.val.valdat_len = result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0; @@ -875,7 +879,7 @@ ypoldproc_next_1_svc(yprequest *argp, struct svc_req *rqstp) result.yp_resptype = YPRESP_KEY_VAL; result.ypresponse_u.yp_resp_key_valtype.val.valdat_val = - result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = ""; + result.ypresponse_u.yp_resp_key_valtype.key.keydat_val = nullbuf; result.ypresponse_u.yp_resp_key_valtype.val.valdat_len = result.ypresponse_u.yp_resp_key_valtype.key.keydat_len = 0; @@ -916,7 +920,7 @@ ypoldproc_poll_1_svc(yprequest *argp, struct svc_req *rqstp) * I hope this is right. */ result.ypresponse_u.yp_resp_map_parmstype.ordernum = 0; - result.ypresponse_u.yp_resp_map_parmstype.peer = ""; + result.ypresponse_u.yp_resp_map_parmstype.peer = nullbuf; if (argp->yp_reqtype != YPREQ_MAP_PARMS) { return(&result); @@ -956,6 +960,8 @@ ypoldproc_push_1_svc(yprequest *argp, struct svc_req *rqstp) /* * Not implemented. */ + argp = NULL; + rqstp = NULL; return (&result); } @@ -968,6 +974,8 @@ ypoldproc_pull_1_svc(yprequest *argp, struct svc_req *rqstp) /* * Not implemented. */ + argp = NULL; + rqstp = NULL; return (&result); } @@ -980,6 +988,8 @@ ypoldproc_get_1_svc(yprequest *argp, struct svc_req *rqstp) /* * Not implemented. */ + argp = NULL; + rqstp = NULL; return (&result); } diff --git a/usr.sbin/ypserv/ypserv.8 b/usr.sbin/ypserv/ypserv.8 index 9d88731..c219263 100644 --- a/usr.sbin/ypserv/ypserv.8 +++ b/usr.sbin/ypserv/ypserv.8 @@ -30,7 +30,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 13, 2009 +.Dd May 29, 2011 .Dt YPSERV 8 .Os .Sh NAME @@ -40,8 +40,10 @@ .Nm .Op Fl n .Op Fl d +.Op Fl h Ar addr .Op Fl P Ar port .Op Fl p Ar path +.Op Fl S .Sh DESCRIPTION .Tn NIS is an RPC-based service designed to allow a number of UNIX-based @@ -259,6 +261,46 @@ sample securenets file might look like this: # allow connections from any host # between 10.0.0.0 to 10.0.15.255 10.0.0.0 255.255.240.0 +# IPv4 addresses in CIDR form +172.16.0.1/16 +# IPv4 host +172.17.0.1/32 +# IPv6 address with netmask +2001:db8:1::1 ffff:ffff:ffff:ffff:: +# IPv6 address with prefix length +2001:db8:2::1/64 +# IPv6 connections from local host +::/128 +# IPv6 host +2001:db8:3::1/128 +.Ed +.Pp +When +.Fl S +flag is specified, another format with the host field and the netmask +field exchanged is used instead. This is for compatibility with an +implementation found in Solaris. An example looks like the following: +.Bd -unfilled -offset indent +# allow connections from local host -- mandatory +255.255.255.255 127.0.0.1 +# allow connections from any host +# on the 192.168.128.0 network +255.255.255.0 192.168.128.0 +# allow connections from any host +# between 10.0.0.0 to 10.0.15.255 +255.255.240.0 10.0.0.0 +# IPv4 addresses in CIDR form +172.16.0.1/16 +# "host" keyword can be used as 255.255.255.255 +host 172.17.0.1 +# IPv6 address with netmask +ffff:ffff:ffff:ffff:: 2001:db8:1::1 +# IPv6 address with prefix length +2001:db8:2::1/64 +# IPv6 connections from local host +::/128 +# "host" keyword can be used as /128 +host 2001:db8:3::1 .Ed .Pp If @@ -434,6 +476,14 @@ flag may be used to specify an alternate root path, allowing the system administrator to move the map files to a different place within the file system. +.It Fl S +Specify +.Pa secrenets +file format as Solaris-compatible. The differences from the native +format are the order of the host and netmask fields, and availability +of +.Dq host +keyword. .El .Sh FILES .Bl -tag -width Pa -compact |