Index: sbin/ipfw/ipfw.8 =================================================================== --- sbin/ipfw/ipfw.8 +++ sbin/ipfw/ipfw.8 @@ -1343,7 +1343,7 @@ with multiple addresses) is provided for convenience only and its use is discouraged. .It Ar addr : Oo Cm not Oc Bro -.Cm any | me | me6 | +.Cm any | me | me4 | me6 | .Cm table Ns Pq Ar name Ns Op , Ns Ar value .Ar | addr-list | addr-set .Brc @@ -1351,7 +1351,11 @@ .It Cm any Matches any IP address. .It Cm me -Matches any IP address configured on an interface in the system. +Matches any IPv4 or IPv6 address configured on an interface in the system. +.It Cm me4 +Matches any IPv4 address configured on an interface in the system. +The address list is evaluated at the time the packet is +analysed. .It Cm me6 Matches any IPv6 address configured on an interface in the system. The address list is evaluated at the time the packet is Index: sbin/ipfw/ipfw2.c =================================================================== --- sbin/ipfw/ipfw2.c +++ sbin/ipfw/ipfw2.c @@ -1208,6 +1208,10 @@ bprintf(bp, "me"); return; } + if (cmd->o.opcode == O_IP_SRC_ME4 || cmd->o.opcode == O_IP_DST_ME4) { + bprintf(bp, "me4"); + return; + } if (cmd->o.opcode == O_IP_SRC_LOOKUP || cmd->o.opcode == O_IP_DST_LOOKUP) { t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1); @@ -1470,6 +1474,7 @@ case O_IP_SRC_LOOKUP: case O_IP_SRC_MASK: case O_IP_SRC_ME: + case O_IP_SRC_ME4: case O_IP_SRC_SET: if (state->flags & HAVE_SRCIP) bprintf(bp, " src-ip"); @@ -1479,6 +1484,7 @@ case O_IP_DST_LOOKUP: case O_IP_DST_MASK: case O_IP_DST_ME: + case O_IP_DST_ME4: case O_IP_DST_SET: if (state->flags & HAVE_DSTIP) bprintf(bp, " dst-ip"); @@ -2125,12 +2131,12 @@ }; static const int src_opcodes[] = { - O_IP_SRC, O_IP_SRC_LOOKUP, O_IP_SRC_MASK, O_IP_SRC_ME, + O_IP_SRC, O_IP_SRC_LOOKUP, O_IP_SRC_MASK, O_IP_SRC_ME, O_IP_SRC_ME4, O_IP_SRC_SET, O_IP6_SRC, O_IP6_SRC_MASK, O_IP6_SRC_ME }; static const int dst_opcodes[] = { - O_IP_DST, O_IP_DST_LOOKUP, O_IP_DST_MASK, O_IP_DST_ME, + O_IP_DST, O_IP_DST_LOOKUP, O_IP_DST_MASK, O_IP_DST_ME, O_IP_DST_ME4, O_IP_DST_SET, O_IP6_DST, O_IP6_DST_MASK, O_IP6_DST_ME }; @@ -3096,7 +3102,7 @@ if (_substrcmp(av, "any") == 0) return; - if (_substrcmp(av, "me") == 0) { + if (_substrcmp(av, "me") == 0 || _substrcmp(av, "me4") == 0) { cmd->o.len |= F_INSN_SIZE(ipfw_insn); return; } @@ -3629,9 +3635,12 @@ cmd->opcode = O_IP_SRC_SET; else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ cmd->opcode = O_IP_SRC_LOOKUP; - else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ - cmd->opcode = O_IP_SRC_ME; - else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ + else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* me/me4 */ + if (strcmp(av, "me4") == 0) + cmd->opcode = O_IP_SRC_ME4; + else + cmd->opcode = O_IP_SRC_ME; + } else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ cmd->opcode = O_IP_SRC; else /* addr/mask */ cmd->opcode = O_IP_SRC_MASK; @@ -3646,9 +3655,12 @@ ; else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ ; - else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ - cmd->opcode = O_IP_DST_ME; - else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ + else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* me/me4 */ + if (strcmp(av, "me4") == 0) + cmd->opcode = O_IP_DST_ME4; + else + cmd->opcode = O_IP_DST_ME; + } else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ cmd->opcode = O_IP_DST; else /* addr/mask */ cmd->opcode = O_IP_DST_MASK; @@ -3695,7 +3707,6 @@ { struct in6_addr a; char *host, *ch, buf[INET6_ADDRSTRLEN]; - ipfw_insn *ret = NULL; int len; /* Copy first address in set if needed */ @@ -3708,17 +3719,16 @@ } else host = av; - if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || + if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || inet_pton(AF_INET6, host, &a) == 1) - ret = add_srcip6(cmd, av, cblen, tstate); - /* XXX: should check for IPv4, not !IPv6 */ - if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || - inet_pton(AF_INET6, host, &a) != 1)) - ret = add_srcip(cmd, av, cblen, tstate); - if (ret == NULL && strcmp(av, "any") != 0) - ret = cmd; + return add_srcip6(cmd, av, cblen, tstate); + else if (proto == IPPROTO_IP || strcmp(av, "me") == 0 || + strcmp(av, "me4") == 0 || inet_pton(AF_INET, host, &a)) + return add_srcip(cmd, av, cblen, tstate); + else if (strcmp(av, "any") != 0) + return cmd; - return ret; + return NULL; } static ipfw_insn * @@ -3726,7 +3736,6 @@ { struct in6_addr a; char *host, *ch, buf[INET6_ADDRSTRLEN]; - ipfw_insn *ret = NULL; int len; /* Copy first address in set if needed */ @@ -3739,17 +3748,16 @@ } else host = av; - if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || + if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || inet_pton(AF_INET6, host, &a) == 1) - ret = add_dstip6(cmd, av, cblen, tstate); - /* XXX: should check for IPv4, not !IPv6 */ - if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || - inet_pton(AF_INET6, host, &a) != 1)) - ret = add_dstip(cmd, av, cblen, tstate); - if (ret == NULL && strcmp(av, "any") != 0) - ret = cmd; + return add_dstip6(cmd, av, cblen, tstate); + else if (proto == IPPROTO_IP || strcmp(av, "me") == 0 || + strcmp(av, "me4") == 0 || inet_pton(AF_INET, host, &a)) + return add_dstip(cmd, av, cblen, tstate); + else if (strcmp(av, "any") != 0) + return cmd; - return ret; + return NULL; } /* Index: sys/netinet/ip_fw.h =================================================================== --- sys/netinet/ip_fw.h +++ sys/netinet/ip_fw.h @@ -169,11 +169,13 @@ O_IP_SRC, /* u32 = IP */ O_IP_SRC_MASK, /* ip = IP/mask */ O_IP_SRC_ME, /* none */ + O_IP_SRC_ME4, /* none */ O_IP_SRC_SET, /* u32=base, arg1=len, bitmap */ O_IP_DST, /* u32 = IP */ O_IP_DST_MASK, /* ip = IP/mask */ O_IP_DST_ME, /* none */ + O_IP_DST_ME4, /* none */ O_IP_DST_SET, /* u32=base, arg1=len, bitmap */ O_IP_SRCPORT, /* (n)port list:mask 4 byte ea */ Index: sys/netpfil/ipfw/ip_fw2.c =================================================================== --- sys/netpfil/ipfw/ip_fw2.c +++ sys/netpfil/ipfw/ip_fw2.c @@ -2128,7 +2128,8 @@ break; case O_IP_SRC_ME: - if (is_ipv4) { + case O_IP_SRC_ME4: + if (is_ipv4 || cmd->opcode == O_IP_SRC_ME4) { match = in_localip(src_ip); break; } @@ -2165,7 +2166,8 @@ break; case O_IP_DST_ME: - if (is_ipv4) { + case O_IP_DST_ME4: + if (is_ipv4 || cmd->opcode == O_IP_DST_ME4) { match = in_localip(dst_ip); break; } Index: sys/netpfil/ipfw/ip_fw_sockopt.c =================================================================== --- sys/netpfil/ipfw/ip_fw_sockopt.c +++ sys/netpfil/ipfw/ip_fw_sockopt.c @@ -1770,7 +1770,9 @@ break; case O_PROTO: case O_IP_SRC_ME: + case O_IP_SRC_ME4: case O_IP_DST_ME: + case O_IP_DST_ME4: case O_LAYER2: case O_IN: case O_FRAG: Index: tests/sys/netpfil/common/Makefile =================================================================== --- tests/sys/netpfil/common/Makefile +++ tests/sys/netpfil/common/Makefile @@ -10,7 +10,8 @@ nat \ tos \ fragments \ - forward + forward \ + ipfw_me4 ${PACKAGE}FILES+= \ utils.subr \ Index: tests/sys/netpfil/common/ipfw_me4.sh =================================================================== --- tests/sys/netpfil/common/ipfw_me4.sh +++ tests/sys/netpfil/common/ipfw_me4.sh @@ -0,0 +1,202 @@ +#- +# SPDX-License-Identifier: BSD-2-Clause-FreeBSD +# +# Copyright (c) 2020 Neel Chauhan +# +# 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 THE AUTHOR 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 THE AUTHOR 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. +# +# $FreeBSD$ +# + +. $(atf_get_srcdir)/utils.subr +. $(atf_get_srcdir)/runner.subr + +me4_allow_head() +{ + atf_set descr 'IPFW me4 allow identifier test' + atf_set require.user root +} + +me4_allow_body() +{ + firewall=$1 + firewall_init $firewall + jname_cli="client" + jname_srv="server" + + epair=$(vnet_mkepair) + vnet_mkjail ${jname_cli} ${epair}a + jexec ${jname_cli} ifconfig ${epair}a 192.0.2.1/30 up + vnet_mkjail ${jname_srv} ${epair}b + jexec ${jname_srv} ifconfig ${epair}b 192.0.2.2/30 up + + firewall_config ${jname_srv} ${firewall} \ + "ipfw" \ + "ipfw -q add 100 allow all from any to any" + firewall_config ${jname_cli} ${firewall} \ + "ipfw" \ + "ipfw -q add 100 allow all from any to any" + atf_check -s exit:0 -o ignore jexec ${jname_cli} ping -c 1 -t 1 192.0.2.2 +} + +me4_allow_cleanup() +{ + firewall=$1 + firewall_cleanup $firewall +} + +me4_deny_head() +{ + atf_set descr 'IPFW me4 deny identifier test' + atf_set require.user root +} + +me4_deny_body() +{ + firewall=$1 + firewall_init $firewall + jname_cli="client" + jname_srv="server" + + epair=$(vnet_mkepair) + vnet_mkjail ${jname_cli} ${epair}a + jexec ${jname_cli} ifconfig ${epair}a 192.0.2.1/30 up + vnet_mkjail ${jname_srv} ${epair}b + jexec ${jname_srv} ifconfig ${epair}b 192.0.2.2/30 up + + firewall_config ${jname_srv} ${firewall} \ + "ipfw" \ + "ipfw -q add 100 deny all from any to me4" + firewall_config ${jname_cli} ${firewall} \ + "ipfw" \ + "ipfw -q add 100 allow all from any to any" + atf_check -s exit:2 -o ignore jexec ${jname_cli} ping -c 1 -t 1 192.0.2.2 + + firewall_config ${jname_srv} ${firewall} \ + "ipfw" \ + "ipfw -q add 100 deny all from me4 to any" + firewall_config ${jname_cli} ${firewall} \ + "ipfw" \ + "ipfw -q add 100 allow all from any to any" + atf_check -s exit:2 -o ignore jexec ${jname_cli} ping -c 1 -t 1 192.0.2.2 +} + +me4_deny_cleanup() +{ + firewall=$1 + firewall_cleanup $firewall +} + +me4_nonlocal_head() +{ + atf_set descr 'IPFW me4 non-local identifier test' + atf_set require.user root +} + +me4_nonlocal_body() +{ + firewall=$1 + firewall_init $firewall + jname_cli="client" + jname_srv="server" + + epair1=$(vnet_mkepair) + epair2=$(vnet_mkepair) + + vnet_mkjail ${jname_cli} ${epair1}a + jexec ${jname_cli} ifconfig ${epair1}a 192.0.2.1/30 up + + vnet_mkjail ${jname_srv} ${epair1}b ${epair2}b + jexec ${jname_srv} ifconfig ${epair1}a 192.0.2.2/30 up + jexec ${jname_srv} ifconfig ${epair2}b 198.51.100.1/30 up + + ifconfig ${epair2}a 198.51.100.2/30 up + + jexec ${jname_srv} sysctl net.inet.ip.forwarding=1 + jexec ${jname_cli} route add -net 198.51.100.0/30 192.0.2.2 + route add -net 192.0.2.0/30 198.51.100.1 + + firewall_config ${jname_srv} ${firewall} \ + "ipfw" \ + "ipfw -q add 100 deny tcp from any to me4 7" \ + "ipfw -q add 200 allow all from any to any" + firewall_config ${jname_cli} ${firewall} \ + "ipfw" \ + "ipfw -q add 100 allow all from any to any" + + atf_check -s exit:2 -o ignore jexec ${jname_cli} ping -c 1 -t 1 198.51.100.2 +} + +me4_nonlocal_cleanup() +{ + firewall=$1 + firewall_cleanup $firewall +} + +me4_ipv6_head() +{ + atf_set descr 'IPFW me4 identifier ipv6 test' + atf_set require.user root +} + +me4_ipv6_body() +{ + firewall=$1 + firewall_init $firewall + jname_cli="client" + jname_srv="server" + + epair=$(vnet_mkepair) + vnet_mkjail ${jname_cli} ${epair}a + jexec ${jname_cli} ifconfig ${epair}a 192.0.2.1/30 up + jexec ${jname_cli} ifconfig ${epair}a inet6 fd7a:803f:cc4b::1/64 up no_dad + vnet_mkjail ${jname_srv} ${epair}b + jexec ${jname_srv} ifconfig ${epair}b 192.0.2.2/30 up + jexec ${jname_srv} ifconfig ${epair}b inet6 fd7a:803f:cc4b::2/64 up no_dad + + firewall_config ${jname_srv} ${firewall} \ + "ipfw" \ + "ipfw -q add 100 deny all from any to me4" \ + "ipfw -q add 200 allow all from any to any" + firewall_config ${jname_cli} ${firewall} \ + "ipfw" \ + "ipfw -q add 100 allow all from any to any" + + atf_check -s exit:0 -o ignore jexec ${jname_cli} ping6 -c 1 -W 1 fd7a:803f:cc4b::2 +} + +me4_ipv6_cleanup() +{ + firewall=$1 + firewall_cleanup $firewall +} + + +setup_tests \ + me4_allow \ + ipfw \ + me4_deny \ + ipfw \ + me4_ipv6 \ + ipfw \ + me4_nonlocal \ + ipfw