From nobody Sun Jul 13 20:41:26 2025 X-Original-To: freebsd-net@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4bgHRb2bRyz61SVX for ; Sun, 13 Jul 2025 20:41:31 +0000 (UTC) (envelope-from chris@cretaforce.gr) Received: from smtp2.cretaforce.gr (smtp2.cretaforce.gr [88.198.109.87]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "*.cretaforce.gr", Issuer "RapidSSL TLS RSA CA G1" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4bgHRY4F4Dz3kyp for ; Sun, 13 Jul 2025 20:41:29 +0000 (UTC) (envelope-from chris@cretaforce.gr) Authentication-Results: mx1.freebsd.org; dkim=pass header.d=cretaforce.gr header.s=cretaforce header.b=ctx0WthY; spf=pass (mx1.freebsd.org: domain of chris@cretaforce.gr designates 88.198.109.87 as permitted sender) smtp.mailfrom=chris@cretaforce.gr; dmarc=pass (policy=none) header.from=cretaforce.gr Received: from server1.cretaforce.gr (server1.cretaforce.gr [94.130.217.104]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) client-signature RSA-PSS (2048 bits)) (Client CN "*.cretaforce.gr", Issuer "RapidSSL TLS RSA CA G1" (verified OK)) by smtp.cretaforce.gr (Postfix) with ESMTPS id C3C9820A7E for ; Sun, 13 Jul 2025 23:41:30 +0300 (EEST) Received: from smtpclient.apple (unknown [149.210.77.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) (Authenticated sender: chris@cretaforce.gr) by server1.cretaforce.gr (Postfix) with ESMTPSA id 3D1E310B88; Sun, 13 Jul 2025 23:41:27 +0300 (EEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cretaforce.gr; s=cretaforce; t=1752439283; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=L5xebfIPUVdeAPH/3nr77uXe6IX/1Wq5pemCfQa6+6w=; b=ctx0WthYjz7XUUVVLVSaT96vkJ/dBuxkI3Toy0YuDJNQo0RUqu1U63krs2ZprvH6q/aok9 DoRDmZv/mfgjp95PhXwm3rhLmS9PyhJRhY6lgmO4Pt/h4oNkcS7LnAO3Pc4mXFjpVWJ515 3P/Qj5ECaTV0XtmWgIDrwR/nCEYe5Go= From: Christos Chatzaras Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable List-Id: Networking and TCP/IP with FreeBSD List-Archive: https://lists.freebsd.org/archives/freebsd-net List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-freebsd-net@FreeBSD.org Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3826.600.51.1.1\)) Subject: Issues with IPFW skipto Rule and Whitelisting Logic Message-Id: <3A01EF48-EBE8-48C3-9C66-6A250A240341@cretaforce.gr> Date: Sun, 13 Jul 2025 23:41:26 +0300 Cc: FreeBSD Questions Mailing List To: freebsd-net X-Mailer: Apple Mail (2.3826.600.51.1.1) X-Spamd-Result: default: False [1.77 / 15.00]; NEURAL_SPAM_LONG(1.00)[1.000]; NEURAL_SPAM_MEDIUM(0.97)[0.972]; DMARC_POLICY_ALLOW(-0.50)[cretaforce.gr,none]; SUBJECT_ENDS_SPACES(0.50)[]; MV_CASE(0.50)[]; R_DKIM_ALLOW(-0.20)[cretaforce.gr:s=cretaforce]; R_SPF_ALLOW(-0.20)[+ip4:88.198.109.87]; NEURAL_HAM_SHORT(-0.10)[-0.101]; MIME_GOOD(-0.10)[text/plain]; RCVD_IN_DNSWL_LOW(-0.10)[88.198.109.87:from]; RCPT_COUNT_TWO(0.00)[2]; DKIM_TRACE(0.00)[cretaforce.gr:+]; ARC_NA(0.00)[]; RCVD_TLS_ALL(0.00)[]; TO_DN_ALL(0.00)[]; MIME_TRACE(0.00)[0:+]; FREEFALL_USER(0.00)[chris]; ASN(0.00)[asn:24940, ipnet:88.198.0.0/16, country:DE]; TO_MATCH_ENVRCPT_SOME(0.00)[]; RCVD_COUNT_TWO(0.00)[2]; FROM_EQ_ENVFROM(0.00)[]; DWL_DNSWL_NONE(0.00)[cretaforce.gr:dkim]; PREVIOUSLY_DELIVERED(0.00)[freebsd-net@freebsd.org]; MID_RHS_MATCH_FROM(0.00)[]; MLMMJ_DEST(0.00)[freebsd-net@freebsd.org]; RCVD_VIA_SMTP_AUTH(0.00)[]; FROM_HAS_DN(0.00)[] X-Rspamd-Queue-Id: 4bgHRY4F4Dz3kyp X-Spamd-Bar: + I am using ipfw with these rules: ---------------- #!/bin/sh # Set rules command prefix cmd=3D"ipfw -q add " cmd2=3D"ipfw -q " # Public interface pif=3D`ifconfig -l | awk '{ print $1 }'` # Flush all rules ipfw -q -f flush # Flush all tables $cmd2 table 1 flush $cmd2 table 3 flush # Allow loopback and deny loopback spoofing $cmd 00010 allow ip from any to any via lo0 $cmd 00020 deny ip from any to 127.0.0.0/8 $cmd 00030 deny ip from 127.0.0.0/8 to any # Catch spoofing from outside. $cmd 00031 deny ip from any to any not antispoof via $pif # Checks stateful rules $cmd 00050 check-state $cmd 00060 deny tcp from any to any established # ALLOW WHITELIST - IGNORE RULE 00100 $cmd2 00070 add skipto 00101 ip from 'table(3)' to any # DENY INCOMING LIST $cmd 00100 reset ip from 'table(1)' to any # ICMP $cmd 01010 allow icmp from any to any out via $pif keep-state $cmd 01011 allow icmp from any to any in via $pif # WWW $cmd 10031 allow tcp from me to any dst-port 443 out via $pif setup = keep-state $cmd 10033 allow tcp from any to me dst-port 443 in via $pif setup = keep-state # Deny everything else, and log it $cmd 56599 deny log all from any to any ---------------- And ipfw list includes: ---------------- 00070 skipto 101 ip from table(3) to any 00100 reset ip from table(1) to any ---------------- Currently, table(1) holds about 1.9 million entries (both individual IPs = and subnets), while table(3) contains about 10,000 entries (also a mix = of single IPs and subnets). These tables are populated using this script few times per day: ---------------- #!/bin/sh tempdir=3D$(mktemp -d /tmp/ipfw.XXXXXX) trap "rm -rf $tempdir" EXIT fetch -q -o "$tempdir/allow.txt" https://example.com/ipfw/allow.txt || = exit 1 fetch -q -o "$tempdir/deny.txt" https://example.com/ipfw/deny.txt || = exit 1 update_table() { table=3D$1 file=3D$2 current_file=3D"$tempdir/current_table_$table.txt" ipfw -q table "$table" list | awk '{print $1}' | sed 's/\/32$//' | = sort > "$current_file" cat "$file" | sed 's/\/32$//' | sort | uniq > = "$tempdir/new_table_$table.txt" comm -13 "$tempdir/new_table_$table.txt" "$current_file" | while = read -r ip; do [ -n "$ip" ] && ipfw -q table "$table" delete "$ip" done comm -23 "$tempdir/new_table_$table.txt" "$current_file" | while = read -r ip; do [ -n "$ip" ] && ipfw -q table "$table" add "$ip" done } update_table 3 "$tempdir/allow.txt" update_table 1 "$tempdir/deny.txt" ---------------- My intended logic is that any IP present in table(3) should always be = allowed, even if it or its subnet also appears in table(1). For instance, 175.178.167.241 is in table(3), while 175.178.0.0/16 is = present in table(1). After rebooting the server and populating the tables by running the = update script for the first time, access from 175.178.167.241 works = correctly. However, after subsequent runs of the update script - which = only updates unrelated entries and does not modify 175.178.167.241 or = 175.178.0.0/16 - access from 175.178.167.241 is no longer permitted. Additionally, when this issue arises, adding 175.178.0.0/16 to table(3) = allows access again. Even after removing that entry, as long as = 175.178.167.241 remains in table(3) and I wait for any active sessions = to clear, access continues to work. Does anyone have any ideas about what could be causing this behavior?=