Path: blob/main/tests/sys/netinet/libalias/2_natout.c
39488 views
/*1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright 2021 Lutz Donnerhacke4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8*9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above12* copyright notice, this list of conditions and the following13* disclaimer in the documentation and/or other materials provided14* with the distribution.15* 3. Neither the name of the copyright holder nor the names of its16* contributors may be used to endorse or promote products derived17* from this software without specific prior written permission.18*19* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND20* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,21* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF22* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE23* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS24* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,25* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED26* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,27* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON28* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR29* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF30* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF31* SUCH DAMAGE.32*/33#include <atf-c.h>34#include <alias.h>35#include <stdio.h>36#include <stdlib.h>3738#include "util.h"3940ATF_TC_WITHOUT_HEAD(1_simplemasq);41ATF_TC_BODY(1_simplemasq, dummy)42{43struct libalias *la = LibAliasInit(NULL);44struct ip *pip;4546ATF_REQUIRE(la != NULL);47LibAliasSetAddress(la, masq);48LibAliasSetMode(la, 0, ~0);4950pip = ip_packet(254, 64);51NAT_CHECK(pip, prv1, ext, masq);52NAT_CHECK(pip, prv2, ext, masq);53NAT_CHECK(pip, prv3, ext, masq);54NAT_CHECK(pip, cgn, ext, masq);55NAT_CHECK(pip, pub, ext, masq);5657free(pip);58LibAliasUninit(la);59}6061ATF_TC_WITHOUT_HEAD(2_unregistered);62ATF_TC_BODY(2_unregistered, dummy)63{64struct libalias *la = LibAliasInit(NULL);65struct ip *pip;6667ATF_REQUIRE(la != NULL);68LibAliasSetAddress(la, masq);69LibAliasSetMode(la, PKT_ALIAS_UNREGISTERED_ONLY, ~0);7071pip = ip_packet(254, 64);72NAT_CHECK(pip, prv1, ext, masq);73NAT_CHECK(pip, prv2, ext, masq);74NAT_CHECK(pip, prv3, ext, masq);75NAT_CHECK(pip, cgn, ext, cgn);76NAT_CHECK(pip, pub, ext, pub);7778/*79* State is only for new connections80* Because they are now active,81* the mode setting should be ignored82*/83LibAliasSetMode(la, 0, PKT_ALIAS_UNREGISTERED_ONLY);84NAT_CHECK(pip, prv1, ext, masq);85NAT_CHECK(pip, prv2, ext, masq);86NAT_CHECK(pip, prv3, ext, masq);87NAT_CHECK(pip, cgn, ext, cgn);88NAT_CHECK(pip, pub, ext, pub);8990free(pip);91LibAliasUninit(la);92}9394ATF_TC_WITHOUT_HEAD(3_cgn);95ATF_TC_BODY(3_cgn, dummy)96{97struct libalias *la = LibAliasInit(NULL);98struct ip *pip;99100ATF_REQUIRE(la != NULL);101LibAliasSetAddress(la, masq);102LibAliasSetMode(la, PKT_ALIAS_UNREGISTERED_CGN, ~0);103104pip = ip_packet(254, 64);105NAT_CHECK(pip, prv1, ext, masq);106NAT_CHECK(pip, prv2, ext, masq);107NAT_CHECK(pip, prv3, ext, masq);108NAT_CHECK(pip, cgn, ext, masq);109NAT_CHECK(pip, pub, ext, pub);110111/*112* State is only for new connections113* Because they are now active,114* the mode setting should be ignored115*/116LibAliasSetMode(la, 0, PKT_ALIAS_UNREGISTERED_CGN);117NAT_CHECK(pip, prv1, ext, masq);118NAT_CHECK(pip, prv2, ext, masq);119NAT_CHECK(pip, prv3, ext, masq);120NAT_CHECK(pip, cgn, ext, masq);121NAT_CHECK(pip, pub, ext, pub);122123free(pip);124LibAliasUninit(la);125}126127ATF_TC_WITHOUT_HEAD(4_udp);128ATF_TC_BODY(4_udp, dummy)129{130struct libalias *la = LibAliasInit(NULL);131struct ip *po, *pi;132struct udphdr *ui, *uo;133uint16_t sport = 0x1234;134uint16_t dport = 0x5678;135uint16_t aport;136137ATF_REQUIRE(la != NULL);138LibAliasSetAddress(la, masq);139LibAliasSetMode(la, 0, ~0);140141/* Query from prv1 */142po = ip_packet(0, 64);143UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);144aport = ntohs(uo->uh_sport);145/* should use a different external port */146ATF_CHECK(aport != sport);147148/* Response */149pi = ip_packet(0, 64);150UDP_UNNAT_CHECK(pi, ui, ext, dport, masq, aport, prv1, sport);151152/* Query from different source with same ports */153UDP_NAT_CHECK(po, uo, prv2, sport, ext, dport, masq);154/* should use a different external port */155ATF_CHECK(uo->uh_sport != htons(aport));156157/* Response to prv2 */158ui->uh_dport = uo->uh_sport;159UDP_UNNAT_CHECK(pi, ui, ext, dport, masq, htons(uo->uh_sport), prv2, sport);160161/* Response to prv1 again */162UDP_UNNAT_CHECK(pi, ui, ext, dport, masq, aport, prv1, sport);163164free(pi);165free(po);166LibAliasUninit(la);167}168169ATF_TC_WITHOUT_HEAD(5_sameport);170ATF_TC_BODY(5_sameport, dummy)171{172struct libalias *la = LibAliasInit(NULL);173struct ip *p;174struct udphdr *u;175uint16_t sport = 0x1234;176uint16_t dport = 0x5678;177uint16_t aport;178179ATF_REQUIRE(la != NULL);180LibAliasSetAddress(la, masq);181LibAliasSetMode(la, PKT_ALIAS_SAME_PORTS, ~0);182183/* Query from prv1 */184p = ip_packet(0, 64);185UDP_NAT_CHECK(p, u, prv1, sport, ext, dport, masq);186aport = ntohs(u->uh_sport);187/* should use the same external port */188ATF_CHECK(aport == sport);189190/* Query from different source with same ports */191UDP_NAT_CHECK(p, u, prv2, sport, ext, dport, masq);192/* should use a different external port */193ATF_CHECK(u->uh_sport != htons(aport));194195free(p);196LibAliasUninit(la);197}198199ATF_TC_WITHOUT_HEAD(6_cleartable);200ATF_TC_BODY(6_cleartable, dummy)201{202struct libalias *la = LibAliasInit(NULL);203struct ip *po, *pi;204struct udphdr *ui __unused, *uo;205uint16_t sport = 0x1234;206uint16_t dport = 0x5678;207uint16_t aport;208209ATF_REQUIRE(la != NULL);210LibAliasSetAddress(la, masq);211LibAliasSetMode(la, PKT_ALIAS_RESET_ON_ADDR_CHANGE, ~0);212LibAliasSetMode(la, PKT_ALIAS_SAME_PORTS, PKT_ALIAS_SAME_PORTS);213LibAliasSetMode(la, PKT_ALIAS_DENY_INCOMING, PKT_ALIAS_DENY_INCOMING);214215/* Query from prv1 */216po = ip_packet(0, 64);217UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);218aport = ntohs(uo->uh_sport);219/* should use the same external port */220ATF_CHECK(aport == sport);221222/* Response */223pi = ip_packet(0, 64);224UDP_UNNAT_CHECK(po, uo, ext, dport, masq, aport, prv1, sport);225226/* clear table by keeping the address */227LibAliasSetAddress(la, ext);228LibAliasSetAddress(la, masq);229230/* Response to prv1 again -> DENY_INCOMING */231UDP_UNNAT_FAIL(pi, ui, ext, dport, masq, aport);232233/* Query from different source with same ports */234UDP_NAT_CHECK(po, uo, prv2, sport, ext, dport, masq);235/* should use the same external port, because it's free */236ATF_CHECK(uo->uh_sport == htons(aport));237238/* Response to prv2 */239UDP_UNNAT_CHECK(po, uo, ext, dport, masq, htons(uo->uh_sport), prv2, sport);240241free(pi);242free(po);243LibAliasUninit(la);244}245246ATF_TC_WITHOUT_HEAD(7_stress);247ATF_TC_BODY(7_stress, dummy)248{249struct libalias *la = LibAliasInit(NULL);250struct ip *p;251struct udphdr *u;252struct {253struct in_addr src, dst;254uint16_t sport, dport, aport;255} *batch;256size_t const batch_size = 1200;257size_t const rounds = 25;258size_t i, j;259260ATF_REQUIRE(la != NULL);261LibAliasSetAddress(la, masq);262263p = ip_packet(0, 64);264265batch = calloc(batch_size, sizeof(*batch));266ATF_REQUIRE(batch != NULL);267for (j = 0; j < rounds; j++) {268for (i = 0; i < batch_size; i++) {269struct in_addr s, d;270switch (i&3) {271case 0: s = prv1; d = ext; break;272case 1: s = prv2; d = pub; break;273case 2: s = prv3; d = ext; break;274case 3: s = cgn; d = pub; break;275}276s.s_addr &= htonl(0xffff0000);277d.s_addr &= htonl(0xffff0000);278batch[i].src.s_addr = s.s_addr | htonl(rand_range(0, 0xffff));279batch[i].dst.s_addr = d.s_addr | htonl(rand_range(0, 0xffff));280batch[i].sport = rand_range(1000, 60000);281batch[i].dport = rand_range(1000, 60000);282}283284for (i = 0; i < batch_size; i++) {285UDP_NAT_CHECK(p, u,286batch[i].src, batch[i].sport,287batch[i].dst, batch[i].dport,288masq);289batch[i].aport = htons(u->uh_sport);290}291292qsort(batch, batch_size, sizeof(*batch), randcmp);293294for (i = 0; i < batch_size; i++) {295UDP_UNNAT_CHECK(p, u,296batch[i].dst, batch[i].dport,297masq, batch[i].aport,298batch[i].src, batch[i].sport);299}300}301302free(batch);303free(p);304LibAliasUninit(la);305}306307ATF_TC_WITHOUT_HEAD(8_portrange);308ATF_TC_BODY(8_portrange, dummy)309{310struct libalias *la = LibAliasInit(NULL);311struct ip *po;312struct udphdr *uo;313uint16_t sport = 0x1234;314uint16_t dport = 0x5678;315uint16_t aport;316317ATF_REQUIRE(la != NULL);318LibAliasSetAddress(la, masq);319LibAliasSetMode(la, 0, ~0);320po = ip_packet(0, 64);321322LibAliasSetAliasPortRange(la, 0, 0); /* reinit like ipfw */323UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);324aport = ntohs(uo->uh_sport);325ATF_CHECK(aport >= 0x8000);326327/* Different larger range */328LibAliasSetAliasPortRange(la, 2000, 3000);329dport++;330UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);331aport = ntohs(uo->uh_sport);332ATF_CHECK(aport >= 2000 && aport < 3000);333334/* Different small range (contains two ports) */335LibAliasSetAliasPortRange(la, 4000, 4001);336dport++;337UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);338aport = ntohs(uo->uh_sport);339ATF_CHECK(aport >= 4000 && aport <= 4001);340341sport++;342UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);343aport = ntohs(uo->uh_sport);344ATF_CHECK(aport >= 4000 && aport <= 4001);345346/* Third port not available in the range */347sport++;348UDP_NAT_FAIL(po, uo, prv1, sport, ext, dport);349350/* Back to normal */351LibAliasSetAliasPortRange(la, 0, 0);352dport++;353UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);354aport = ntohs(uo->uh_sport);355ATF_CHECK(aport >= 0x8000);356357free(po);358LibAliasUninit(la);359}360361ATF_TC_WITHOUT_HEAD(9_udp_eim_mapping);362ATF_TC_BODY(9_udp_eim_mapping, dummy)363{364struct libalias *la = LibAliasInit(NULL);365struct ip *po, *po2, *po3;366struct udphdr *uo, *uo2, *uo3;367uint16_t sport = 0x1234;368uint16_t dport = 0x5678;369uint16_t dport2 = 0x6789;370uint16_t aport, aport2, aport3;371372ATF_REQUIRE(la != NULL);373LibAliasSetAddress(la, masq);374LibAliasSetMode(la, PKT_ALIAS_UDP_EIM, ~0);375376po = ip_packet(0, 64);377UDP_NAT_CHECK(po, uo, prv1, sport, ext, dport, masq);378aport = ntohs(uo->uh_sport);379380/* Change of dst port shouldn't change alias port */381po2 = ip_packet(0, 64);382UDP_NAT_CHECK(po2, uo2, prv1, sport, ext, dport2, masq);383aport2 = ntohs(uo2->uh_sport);384ATF_CHECK_EQ_MSG(aport, aport2,385"NAT uses address- and port-dependent mapping (%uh -> %uh)",386aport, aport2);387388/* Change of dst address shouldn't change alias port */389po3 = ip_packet(0, 64);390UDP_NAT_CHECK(po3, uo3, prv1, sport, pub, dport, masq);391aport3 = ntohs(uo3->uh_sport);392ATF_CHECK_EQ_MSG(aport, aport3, "NAT uses address-dependent mapping");393394free(po);395free(po2);396free(po3);397LibAliasUninit(la);398}399400ATF_TC_WITHOUT_HEAD(10_udp_eim_out_in);401ATF_TC_BODY(10_udp_eim_out_in, dummy)402{403struct libalias *la = LibAliasInit(NULL);404struct ip *po, *po2, *po3;405struct udphdr *uo, *uo2, *uo3;406uint16_t sport = 0x1234;407uint16_t dport = 0x5678;408uint16_t dport2 = 0x6789;409uint16_t aport;410411ATF_REQUIRE(la != NULL);412LibAliasSetAddress(la, masq);413LibAliasSetMode(la, PKT_ALIAS_UDP_EIM, ~0);414415po = ip_packet(0, 64);416UDP_NAT_CHECK(po, uo, prv1, sport, pub, dport, masq);417aport = ntohs(uo->uh_sport);418419/* Accepts inbound packets from different port */420po2 = ip_packet(0, 64);421UDP_UNNAT_CHECK(po2, uo2, pub, dport2, masq, aport, prv1, sport);422423/* Accepts inbound packets from differerent host and port */424po3 = ip_packet(0, 64);425UDP_UNNAT_CHECK(po3, uo3, pub2, dport2, masq, aport, prv1, sport);426427free(po);428free(po2);429free(po3);430LibAliasUninit(la);431}432433ATF_TC_WITHOUT_HEAD(11_udp_eim_with_deny_incoming);434ATF_TC_BODY(11_udp_eim_with_deny_incoming, dummy)435{436struct libalias *la = LibAliasInit(NULL);437struct ip *po, *po2, *po3, *po4;438struct udphdr *uo;439uint16_t sport = 0x1234;440uint16_t dport = 0x5678;441uint16_t dport2 = 0x6789;442uint16_t aport;443int ret;444445ATF_REQUIRE(la != NULL);446LibAliasSetAddress(la, masq);447LibAliasSetMode(la,448PKT_ALIAS_UDP_EIM | PKT_ALIAS_DENY_INCOMING,449~0);450451po = ip_packet(0, 64);452UDP_NAT_CHECK(po, uo, prv1, sport, pub, dport, masq);453aport = ntohs(uo->uh_sport);454455po2 = ip_packet(0, 64);456po2->ip_src = pub;457po2->ip_dst = masq;458set_udp(po2, dport, aport);459ret = LibAliasIn(la, po2, 64);460ATF_CHECK_EQ_MSG(PKT_ALIAS_OK, ret,461"LibAliasIn failed with error %d\n", ret);462463po3 = ip_packet(0, 64);464po3->ip_src = pub;465po3->ip_dst = masq;466set_udp(po3, dport2, aport);467ret = LibAliasIn(la, po3, 64);468ATF_CHECK_EQ_MSG(PKT_ALIAS_IGNORED, ret,469"incoming packet from different port not ignored "470"with PKT_ALIAS_DENY_INCOMING");471472po4 = ip_packet(0, 64);473po4->ip_src = pub2;474po4->ip_dst = masq;475set_udp(po4, dport2, aport);476ret = LibAliasIn(la, po4, 64);477ATF_CHECK_EQ_MSG(PKT_ALIAS_IGNORED, ret,478"incoming packet from different address and port not ignored "479"with PKT_ALIAS_DENY_INCOMING");480481free(po);482free(po2);483free(po3);484free(po4);485LibAliasUninit(la);486}487488ATF_TC_WITHOUT_HEAD(12_udp_eim_hairpinning);489ATF_TC_BODY(12_udp_eim_hairpinning, dummy)490{491struct libalias *la = LibAliasInit(NULL);492struct ip *po, *po2, *po3;493struct udphdr *uo, *uo2, *uo3;494uint16_t sport1 = 0x1234;495uint16_t sport2 = 0x2345;496uint16_t dport = 0x5678;497uint16_t extport1, extport2;498499ATF_REQUIRE(la != NULL);500LibAliasSetAddress(la, masq);501LibAliasSetMode(la, PKT_ALIAS_UDP_EIM, ~0);502503/* prv1 sends out somewhere (eg. a STUN server) */504po = ip_packet(0, 64);505UDP_NAT_CHECK(po, uo, prv1, sport1, pub, dport, masq);506extport1 = ntohs(uo->uh_sport);507508/* prv2, behind the same NAT as prv1, also sends out somewhere */509po2 = ip_packet(0, 64);510UDP_NAT_CHECK(po2, uo2, prv2, sport2, pub, dport, masq);511extport2 = ntohs(uo2->uh_sport);512513/* hairpin: prv1 sends to prv2's external NAT mapping514* (unaware it could address it internally instead).515*/516po3 = ip_packet(0, 64);517UDP_NAT_CHECK(po3, uo3, prv1, sport1, masq, extport2, masq);518UDP_UNNAT_CHECK(po3, uo3, masq, extport1, masq, extport2,519prv2, sport2);520521free(po);522free(po2);523free(po3);524LibAliasUninit(la);525}526527ATF_TP_ADD_TCS(natout)528{529/* Use "dd if=/dev/random bs=2 count=1 | od -x" to reproduce */530srand(0x0b61);531532ATF_TP_ADD_TC(natout, 1_simplemasq);533ATF_TP_ADD_TC(natout, 2_unregistered);534ATF_TP_ADD_TC(natout, 3_cgn);535ATF_TP_ADD_TC(natout, 4_udp);536ATF_TP_ADD_TC(natout, 5_sameport);537ATF_TP_ADD_TC(natout, 6_cleartable);538ATF_TP_ADD_TC(natout, 7_stress);539ATF_TP_ADD_TC(natout, 8_portrange);540ATF_TP_ADD_TC(natout, 9_udp_eim_mapping);541ATF_TP_ADD_TC(natout, 10_udp_eim_out_in);542ATF_TP_ADD_TC(natout, 11_udp_eim_with_deny_incoming);543ATF_TP_ADD_TC(natout, 12_udp_eim_hairpinning);544545return atf_no_error();546}547548549