diff options
author | Robert Mustacchi <rm@joyent.com> | 2014-05-08 13:40:41 +0000 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2014-05-14 23:19:27 +0000 |
commit | 71f4a70d7ca4c7143accc42525bcec0f4da7f4d0 (patch) | |
tree | d6595307655c9257e04f8ba4a94f6c0ead2238fd | |
parent | 74d5b5a7ae8758330255bfe28ab2399ad19fdd0e (diff) | |
download | illumos-joyent-71f4a70d7ca4c7143accc42525bcec0f4da7f4d0.tar.gz |
OS-2993 Need IPv6 antispoof prefixes
-rw-r--r-- | usr/src/lib/libdladm/common/linkprop.c | 85 | ||||
-rw-r--r-- | usr/src/test/util-tests/runfiles/default.run | 1 | ||||
-rw-r--r-- | usr/src/test/util-tests/tests/Makefile | 2 | ||||
-rw-r--r-- | usr/src/test/util-tests/tests/dladm/Makefile | 40 | ||||
-rw-r--r-- | usr/src/test/util-tests/tests/dladm/allowed-ips.ksh | 207 | ||||
-rw-r--r-- | usr/src/uts/common/io/mac/mac_protect.c | 39 | ||||
-rw-r--r-- | usr/src/uts/common/sys/mac_flow.h | 2 |
7 files changed, 317 insertions, 59 deletions
diff --git a/usr/src/lib/libdladm/common/linkprop.c b/usr/src/lib/libdladm/common/linkprop.c index b89860e1c1..5a6eed57d6 100644 --- a/usr/src/lib/libdladm/common/linkprop.c +++ b/usr/src/lib/libdladm/common/linkprop.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #include <stdlib.h> @@ -2348,33 +2348,6 @@ get_protection(dladm_handle_t handle, prop_desc_t *pdp, return (DLADM_STATUS_OK); } -static uint32_t -nbits_to_mask(int nbits) -{ - int i; - uint_t mask = 0; - - for (i = 0; i < nbits; i++) { - mask >>= 1; - mask |= 0x80000000; - } - - return (mask); -} - -static uint32_t -mask_to_nbits(uint32_t mask) -{ - uint_t nbits = 0; - - while (mask != 0) { - nbits++; - mask <<= 1; - } - - return (nbits); -} - /* ARGSUSED */ static dladm_status_t get_allowedips(dladm_handle_t handle, prop_desc_t *pdp, @@ -2402,20 +2375,19 @@ get_allowedips(dladm_handle_t handle, prop_desc_t *pdp, for (i = 0; i < p->mp_ipaddrcnt; i++) { if (p->mp_ipaddrs[i].ip_version == IPV4_VERSION) { ipaddr_t v4addr; - uint32_t mask; v4addr = V4_PART_OF_V6(p->mp_ipaddrs[i].ip_addr); - mask = p->mp_ipaddrs[i].ip_v4netmask; (void) dladm_ipv4addr2str(&v4addr, prop_val[i]); - if (mask != 0) { - int len = strlen(prop_val[i]); - (void) sprintf(prop_val[i] + len, "/%d", - mask_to_nbits(mask)); - } } else { (void) dladm_ipv6addr2str(&p->mp_ipaddrs[i].ip_addr, prop_val[i]); } + if (p->mp_ipaddrs[i].ip_netmask != 0) { + int len = strlen(prop_val[i]); + (void) sprintf(prop_val[i] + len, "/%d", + p->mp_ipaddrs[i].ip_netmask); + } + } *val_cnt = p->mp_ipaddrcnt; return (DLADM_STATUS_OK); @@ -2464,7 +2436,7 @@ check_single_ip(char *buf, mac_ipaddr_t *addr) in6_addr_t v6addr; boolean_t isv4 = B_TRUE; char *p; - uint32_t mask; + uint32_t mask = 0; /* * If the IP address is in CIDR format, parse the bits component @@ -2473,17 +2445,15 @@ check_single_ip(char *buf, mac_ipaddr_t *addr) */ if ((p = strchr(buf, '/')) != NULL) { char *end = NULL; - long msk; *p++ = '\0'; if (!isdigit(*p)) return (DLADM_STATUS_INVALID_IP); - msk = strtol(p, &end, 10); + mask = strtol(p, &end, 10); if (end != NULL && *end != '\0') return (DLADM_STATUS_INVALID_IP); - if (msk > 32 || msk < 1) + if (mask > 128|| mask < 1) return (DLADM_STATUS_INVALID_IP); - mask = nbits_to_mask((int)msk); } status = dladm_str2ipv4addr(buf, &v4addr); @@ -2502,23 +2472,52 @@ check_single_ip(char *buf, mac_ipaddr_t *addr) IN6_IPADDR_TO_V4MAPPED(v4addr, &addr->ip_addr); addr->ip_version = IPV4_VERSION; if (p != NULL) { + uint32_t smask; + + /* + * Validate the netmask is in the proper range for v4 + */ + if (mask > 32 || mask < 1) + return (DLADM_STATUS_INVALID_IP); + /* * We have a CIDR style address, confirm that only the * network number is set. */ - if (htonl(v4addr) & ~mask) + smask = 0xFFFFFFFFu << (32 - mask); + if (htonl(v4addr) & ~smask) return (DLADM_STATUS_INVALID_IP); - addr->ip_v4netmask = mask; } + addr->ip_netmask = mask; } else { if (IN6_IS_ADDR_UNSPECIFIED(&v6addr)) return (DLADM_STATUS_INVALID_IP); - if (p != NULL) + if (IN6_IS_ADDR_V4MAPPED_ANY(&v6addr)) return (DLADM_STATUS_INVALID_IP); + if (p != NULL) { + int i, off, high; + + /* + * Note that the address in our buffer is stored in + * network byte order. + */ + off = 0; + for (i = 3; i >= 0; i--) { + high = ffsl(ntohl(v6addr._S6_un._S6_u32[i])); + if (high != 0) + break; + off += 32; + } + off += high; + if (128 - off >= mask) + return (DLADM_STATUS_INVALID_IP); + } + addr->ip_addr = v6addr; addr->ip_version = IPV6_VERSION; + addr->ip_netmask = mask; } return (DLADM_STATUS_OK); } diff --git a/usr/src/test/util-tests/runfiles/default.run b/usr/src/test/util-tests/runfiles/default.run index 638ba93ce1..3122bb6640 100644 --- a/usr/src/test/util-tests/runfiles/default.run +++ b/usr/src/test/util-tests/runfiles/default.run @@ -23,4 +23,5 @@ post = outputdir = /var/tmp/test_results [/opt/util-tests/tests/printf_test] +[/opt/util-tests/tests/allowed-ips] diff --git a/usr/src/test/util-tests/tests/Makefile b/usr/src/test/util-tests/tests/Makefile index 41307ba8e4..86d9e01fc8 100644 --- a/usr/src/test/util-tests/tests/Makefile +++ b/usr/src/test/util-tests/tests/Makefile @@ -14,6 +14,6 @@ # Copyright 2014 Garrett D'Amore <garrett@damore.org> # -SUBDIRS = printf +SUBDIRS = dladm printf include $(SRC)/test/Makefile.com diff --git a/usr/src/test/util-tests/tests/dladm/Makefile b/usr/src/test/util-tests/tests/dladm/Makefile new file mode 100644 index 0000000000..df3997656c --- /dev/null +++ b/usr/src/test/util-tests/tests/dladm/Makefile @@ -0,0 +1,40 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2014 Joyent, Inc. All rights reserved. +# + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/test/Makefile.com + +ROOTOPTPKG = $(ROOT)/opt/util-tests/tests +PROG = allowed-ips + +ROOTPROG = $(PROG:%=$(ROOTOPTPKG)/%) + +all: + +install: $(ROOTPROG) + +lint: + +clobber: clean + +clean: + +$(CMDS): $(TESTDIR) + +$(ROOTOPTPKG): + $(INS.dir) + +$(ROOTOPTPKG)/%: %.ksh $(ROOTOPTPKG) + $(INS.rename) diff --git a/usr/src/test/util-tests/tests/dladm/allowed-ips.ksh b/usr/src/test/util-tests/tests/dladm/allowed-ips.ksh new file mode 100644 index 0000000000..866b8c7966 --- /dev/null +++ b/usr/src/test/util-tests/tests/dladm/allowed-ips.ksh @@ -0,0 +1,207 @@ +#!/bin/ksh +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2014, Joyent, Inc. +# + +ai_arg0="$(basename $0)" +ai_stub="teststub$$" +ai_vnic="testvnic$$" + +function fatal +{ + typeset msg="$*" + [[ -z "$msg" ]] && msg="failed" + echo "TEST_FAIL: $vt_arg0: $msg" >&2 + exit 1 +} + +function setup +{ + dladm create-etherstub $ai_stub || fatal "failed to create etherstub" + dladm create-vnic -l $ai_stub $ai_vnic || fatal "failed to create vnic" +} + +function cleanup +{ + dladm delete-vnic $ai_vnic || fatal "failed to remove vnic" + dladm delete-etherstub $ai_stub || fatal "failed to remove etherstub" +} + +function runtest +{ + dladm set-linkprop -p allowed-ips="$@" $ai_vnic 2>/dev/null +} + +function epass +{ + runtest $* || fatal "allowed-ips=$* failed, expected success\n" +} + +function efail +{ + runtest $* && fatal "allowed-ips=$* succeeded, expected failure\n" +} + +# +# Run through all IPv6 prefixes for validity with a token prefix +# +function allv6 +{ + typeset i; + for ((i = 1; i <= 128; i++)); do + epass "8000::/$i" + done +} + +# +# Run through all of the v6 prefixes except /128 and ensure that they fail for +# a given IPv6 address because the other bits are set. +# +function v6specific +{ + typeset i; + for ((i = 0; i < 128; i++)); do + efail 2600:3c00::f03c:91ff:fe96:a267/$i + done +} + +setup + +# Basic IPv4 single and multiple IPs +efail 0.0.0.0 +epass 127.0.0.1 +epass 127.0.0.1,127.0.0.2 +efail 127.0.0.1,127.0.0.1 +epass 10.167.169.23 +epass 11.167.169.23 +epass 12.167.169.23 +epass 10.167.169.23,11.167.169.23,12.167.169.23 +efail 256.1.1.1 +efail 1.256.1.1 +efail 1.1.256.1 +efail 1.1.1.256 +efail 300.300.300.300 +efail 300.300.300.300,1.1.1.1 +efail 1.1.1.1,300.300.300.300 +efail 3.-3.3.-3 + +# Basic IPv4 prefixes +efail 0.0.0.0/0 +epass 127.0.0.0/8 +efail 127.0.0.1/8 +epass 128.0.0.0/1 +epass 128.0.0.0/2 +epass 128.0.0.0/3 +epass 128.0.0.0/4 +epass 128.0.0.0/5 +epass 128.0.0.0/6 +epass 128.0.0.0/7 +epass 128.0.0.0/8 +epass 128.0.0.0/9 +epass 128.0.0.0/10 +epass 128.0.0.0/11 +epass 128.0.0.0/12 +epass 128.0.0.0/13 +epass 128.0.0.0/14 +epass 128.0.0.0/15 +epass 128.0.0.0/16 +epass 128.0.0.0/17 +epass 128.0.0.0/18 +epass 128.0.0.0/19 +epass 128.0.0.0/20 +epass 128.0.0.0/21 +epass 128.0.0.0/22 +epass 128.0.0.0/23 +epass 128.0.0.0/24 +epass 128.0.0.0/25 +epass 128.0.0.0/26 +epass 128.0.0.0/27 +epass 128.0.0.0/28 +epass 128.0.0.0/29 +epass 128.0.0.0/30 +epass 128.0.0.0/21 +epass 128.0.0.0/32 + +efail 128.0.0.1/2 +efail 128.0.0.1/4 +efail 128.0.0.1/8 +efail 128.0.0.1/10 +efail 128.0.0.1/12 +efail 128.0.0.1/14 +efail 128.0.0.1/16 +efail 128.0.0.1/18 +efail 128.0.0.1/20 +efail 128.0.0.1/22 +efail 128.0.0.1/24 +efail 128.0.0.1/28 +efail 128.0.0.1/30 +epass 128.0.0.1/32 + +epass 10.0.0.0/30 +epass 10.0.0.4/30 +epass 10.0.0.8/30 +epass 10.0.0.12/30 +epass 10.0.0.16/30 +epass 10.0.0.20/30 + +efail 10.0.0.1/30 +efail 10.0.0.5/30 +efail 10.0.0.9/30 +efail 10.0.0.13/30 +efail 10.0.0.17/30 +efail 10.0.0.21/30 + +epass 10.99.99.0/24,10.88.88.0/24,10.77.7.0/24 +epass 10.99.99.7/32,10.168.0.0/16 + +efail 10.99.99.7/33 +efail 10.99.99.7/-1 +efail 10.99.99.7/ +efail 10.99.99.7/0 + +# Basic IPv6 Addresss +efail :: +efail 1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1 +efail dead:beef::gg +epass ::1 +epass ::127.0.0.1 +epass ::10.0.0.0 +efail ::0.0.0.0 +efail ::ffff:0.0.0.0 +epass ::ffff:10.123.167.169 +epass 2600:3c00::f03c:91ff:fe96:a264 + +# IPv6 Prefixes + +efail ::/128 +efail 2600:3c00::f03c:91ff:fe96:a264/129 +efail 2600:3c00::f03c:91ff:fe96:a264/-1 +efail 2600:3c00::f03c:91ff:fe96:a264/- +efail 2600:3c00::f03c:91ff:fe96:a264/ +efail ::1/1 +efail ::1/20 + +allv6 +v6specific + +epass 2600:3c00::f03c:91ff:fe96:a264/128 +epass 2600:3c00::/64 + +efail fe80::8:20ff:fead:3361/10 +efail fe80::1/10 +epass fe80::/15 +epass fe82::/15 + +cleanup +printf "TEST PASS: $ai_arg0" diff --git a/usr/src/uts/common/io/mac/mac_protect.c b/usr/src/uts/common/io/mac/mac_protect.c index 5016cc2665..3c3266ac1d 100644 --- a/usr/src/uts/common/io/mac/mac_protect.c +++ b/usr/src/uts/common/io/mac/mac_protect.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #include <sys/strsun.h> @@ -1534,18 +1534,19 @@ ipnospoof_check_v4(mac_client_impl_t *mcip, mac_protect_t *protect, mac_ipaddr_t *v4addr = &protect->mp_ipaddrs[i]; if (v4addr->ip_version == IPV4_VERSION) { - if (v4addr->ip_v4netmask != 0) { - /* - * Since we have a netmask we know this entry - * signifies the entire subnet. Check if the - * given address is on the subnet. - */ - if (htonl(V4_PART_OF_V6(v4addr->ip_addr)) == - (htonl(*addr) & v4addr->ip_v4netmask)) - return (B_TRUE); - } else if (V4_PART_OF_V6(v4addr->ip_addr) == *addr) { + uint32_t mask; + + ASSERT(v4addr->ip_netmask >= 0 && + v4addr->ip_netmask <= 32); + mask = 0xFFFFFFFFu << (32 - v4addr->ip_netmask); + /* + * Since we have a netmask we know this entry + * signifies the entire subnet. Check if the + * given address is on the subnet. + */ + if (htonl(V4_PART_OF_V6(v4addr->ip_addr)) == + (htonl(*addr) & mask)) return (B_TRUE); - } } } return (protect->mp_ipaddrcnt == 0 ? @@ -1571,7 +1572,8 @@ ipnospoof_check_v6(mac_client_impl_t *mcip, mac_protect_t *protect, mac_ipaddr_t *v6addr = &protect->mp_ipaddrs[i]; if (v6addr->ip_version == IPV6_VERSION && - IN6_ARE_ADDR_EQUAL(&v6addr->ip_addr, addr)) + IN6_ARE_PREFIXEDADDR_EQUAL(&v6addr->ip_addr, addr, + v6addr->ip_netmask)) return (B_TRUE); } return (protect->mp_ipaddrcnt == 0 ? @@ -2107,14 +2109,23 @@ validate_ips(mac_protect_t *p) /* * The unspecified address is implicitly allowed - * so there's no need to add it to the list. + * so there's no need to add it to the list. Also, validate that + * the netmask, if any, is sane for the specific version of IP. */ if (addr->ip_version == IPV4_VERSION) { if (V4_PART_OF_V6(addr->ip_addr) == INADDR_ANY) return (EINVAL); + if (addr->ip_netmask > 32) + return (EINVAL); } else if (addr->ip_version == IPV6_VERSION) { if (IN6_IS_ADDR_UNSPECIFIED(&addr->ip_addr)) return (EINVAL); + + if (IN6_IS_ADDR_V4MAPPED_ANY(&addr->ip_addr)) + return (EINVAL); + + if (addr->ip_netmask > 128) + return (EINVAL); } else { /* invalid ip version */ return (EINVAL); diff --git a/usr/src/uts/common/sys/mac_flow.h b/usr/src/uts/common/sys/mac_flow.h index 4d7905de18..d43186f2b0 100644 --- a/usr/src/uts/common/sys/mac_flow.h +++ b/usr/src/uts/common/sys/mac_flow.h @@ -158,7 +158,7 @@ typedef enum { typedef struct mac_ipaddr_s { uint32_t ip_version; in6_addr_t ip_addr; - uint32_t ip_v4netmask; + uint8_t ip_netmask; } mac_ipaddr_t; typedef enum { |