-
Notifications
You must be signed in to change notification settings - Fork 1
fix: address ipv6 validation and filtering review comments #69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ import { Command } from 'commander'; | |
| import * as path from 'path'; | ||
| import * as os from 'os'; | ||
| import * as fs from 'fs'; | ||
| import { isIPv6 } from 'net'; | ||
| import { WrapperConfig, LogLevel } from './types'; | ||
| import { logger } from './logger'; | ||
| import { | ||
|
|
@@ -89,19 +90,12 @@ export function isValidIPv4(ip: string): boolean { | |
| } | ||
|
|
||
| /** | ||
| * Validates that a string is a valid IPv6 address | ||
| * Validates that a string is a valid IPv6 address using Node.js built-in net module | ||
| * @param ip - String to validate | ||
| * @returns true if the string is a valid IPv6 address | ||
| */ | ||
| export function isValidIPv6(ip: string): boolean { | ||
| // Comprehensive IPv6 validation covering: | ||
| // - Full form: 2001:0db8:85a3:0000:0000:8a2e:0370:7334 | ||
| // - Compressed form: 2001:db8:85a3::8a2e:370:7334 | ||
| // - Loopback: ::1 | ||
| // - Unspecified: :: | ||
| // - IPv4-mapped: ::ffff:192.0.2.1 | ||
| const ipv6Regex = /^(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}|:(?::[0-9a-fA-F]{1,4}){1,7}|::)$/; | ||
| return ipv6Regex.test(ip); | ||
| return isIPv6(ip); | ||
| } | ||
|
Comment on lines
97
to
99
|
||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -270,6 +270,41 @@ export async function setupHostIptables(squidIp: string, squidPort: number, dnsS | |||||||||||||||||
| // Set up IPv6 chain if we have IPv6 DNS servers | ||||||||||||||||||
| await setupIpv6Chain(bridgeName); | ||||||||||||||||||
|
|
||||||||||||||||||
| // IPv6 chain needs to mirror IPv4 chain's comprehensive filtering | ||||||||||||||||||
| // This prevents IPv6 from becoming an unfiltered bypass path | ||||||||||||||||||
|
|
||||||||||||||||||
| // Note: Squid proxy rule is omitted for IPv6 since Squid runs on IPv4 only | ||||||||||||||||||
|
|
||||||||||||||||||
| // 1. Allow established and related connections (return traffic) | ||||||||||||||||||
| await execa('ip6tables', [ | ||||||||||||||||||
| '-t', 'filter', '-A', CHAIN_NAME_V6, | ||||||||||||||||||
| '-m', 'conntrack', '--ctstate', 'ESTABLISHED,RELATED', | ||||||||||||||||||
| '-j', 'ACCEPT', | ||||||||||||||||||
| ]); | ||||||||||||||||||
|
|
||||||||||||||||||
| // 2. Allow localhost/loopback traffic | ||||||||||||||||||
| await execa('ip6tables', [ | ||||||||||||||||||
| '-t', 'filter', '-A', CHAIN_NAME_V6, | ||||||||||||||||||
| '-o', 'lo', | ||||||||||||||||||
| '-j', 'ACCEPT', | ||||||||||||||||||
| ]); | ||||||||||||||||||
|
|
||||||||||||||||||
| await execa('ip6tables', [ | ||||||||||||||||||
| '-t', 'filter', '-A', CHAIN_NAME_V6, | ||||||||||||||||||
| '-d', '::1/128', | ||||||||||||||||||
| '-j', 'ACCEPT', | ||||||||||||||||||
| ]); | ||||||||||||||||||
|
|
||||||||||||||||||
|
||||||||||||||||||
| // Allow essential ICMPv6 (required for IPv6 functionality) | |
| await execa('ip6tables', [ | |
| '-t', 'filter', '-A', CHAIN_NAME_V6, | |
| '-p', 'ipv6-icmp', | |
| '-j', 'ACCEPT', | |
| ]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't this test overly simplified?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the check is intentionally simple because the DNS servers passed to this script via
AWF_DNS_SERVERSare already validated insrc/cli.tsusing Node.js'snet.isIPv6()before the container starts. The shell script only needs to distinguish between pre-validated IPv4 and IPv6 addresses, so checking for a colon is sufficient - IPv6 addresses always contain colons, IPv4 never do.If you'd prefer more robust validation in the shell script itself, I can add a more comprehensive check using regex or by attempting to parse with standard utilities.