Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion src/squid-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,7 @@ describe('generateSquidConfig', () => {
};
const result = generateSquidConfig(config);
expect(result).toContain('acl allowed_domains dstdomain');
expect(result).not.toContain('dstdom_regex');
expect(result).not.toContain('acl allowed_domains_regex dstdom_regex');
expect(result).toContain('http_access deny !allowed_domains');
expect(result).not.toContain('allowed_domains_regex');
});
Expand Down Expand Up @@ -1198,6 +1198,66 @@ describe('generateSquidConfig', () => {
});
});

describe('Direct IP bypass protection', () => {
const defaultPort = 3128;

it('should include IPv4 deny ACL in generated config', () => {
const config: SquidConfig = {
domains: ['github.com'],
port: defaultPort,
};
const result = generateSquidConfig(config);
expect(result).toContain('acl dst_ipv4 dstdom_regex');
expect(result).toContain('http_access deny dst_ipv4');
});

it('should include IPv6 deny ACL in generated config', () => {
const config: SquidConfig = {
domains: ['github.com'],
port: defaultPort,
};
const result = generateSquidConfig(config);
expect(result).toContain('acl dst_ipv6 dstdom_regex');
expect(result).toContain('http_access deny dst_ipv6');
});

it('should place IP deny rules before domain allow/deny rules', () => {
const config: SquidConfig = {
domains: ['github.com'],
port: defaultPort,
};
const result = generateSquidConfig(config);
const ipv4DenyPos = result.indexOf('http_access deny dst_ipv4');
const domainDenyPos = result.indexOf('http_access deny !allowed_domains');
expect(ipv4DenyPos).toBeGreaterThan(-1);
expect(domainDenyPos).toBeGreaterThan(-1);
expect(ipv4DenyPos).toBeLessThan(domainDenyPos);
});

it('should include IP deny rules even with no domains configured', () => {
const config: SquidConfig = {
domains: [],
port: defaultPort,
};
const result = generateSquidConfig(config);
expect(result).toContain('http_access deny dst_ipv4');
expect(result).toContain('http_access deny dst_ipv6');
});

it('should include IP deny rules in SSL Bump mode', () => {
const config: SquidConfig = {
domains: ['github.com'],
port: defaultPort,
sslBump: true,
caFiles: { certPath: '/tmp/cert.pem', keyPath: '/tmp/key.pem' },
sslDbPath: '/tmp/ssl_db',
};
const result = generateSquidConfig(config);
expect(result).toContain('http_access deny dst_ipv4');
expect(result).toContain('http_access deny dst_ipv6');
});
});

describe('Port validation in generateSquidConfig', () => {
it('should accept valid single ports', () => {
expect(() => {
Expand Down
7 changes: 7 additions & 0 deletions src/squid-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,13 @@ acl localnet src fe80::/10

${portAclsAndRules}

# Deny CONNECT to raw IP addresses (IPv4 and IPv6)
# Prevents bypassing domain-based filtering via direct IP connections
acl dst_ipv4 dstdom_regex ^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$
acl dst_ipv6 dstdom_regex ^\\[?[0-9a-fA-F:]+\\]?$
http_access deny dst_ipv4
http_access deny dst_ipv6

${accessRulesSection}# Deny requests to unknown domains (not in allow-list)
# This applies to all sources including localnet
${denyRule}
Expand Down
Loading