Skip to content

Commit bdb1100

Browse files
committed
merge: v0.2.0
2 parents 48a6e4d + 13b4c18 commit bdb1100

6 files changed

Lines changed: 86 additions & 19 deletions

File tree

.github/workflows/package.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: Publish Package to npmjs
2+
on:
3+
release:
4+
types: [published]
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v4
10+
# Setup .npmrc file to publish to npm
11+
- uses: actions/setup-node@v4
12+
with:
13+
node-version: '20.x'
14+
registry-url: 'https://registry.npmjs.org'
15+
- run: npm ci
16+
- run: npm publish --provenance --access public
17+
env:
18+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

dispatcher.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,36 @@
1-
import { createRandomSocket } from './socket.js'
1+
import { generateRandomIP } from './ip.js';
2+
import { createRandomSocket, createSocketFromHostname } from './socket.js'
23
import { Agent, buildConnector } from 'undici'
34

45
// taken from `fetch-socks`, many thanks
56
function resolvePort(protocol, port) {
67
return port ? Number.parseInt(port) : protocol === "http:" ? 80 : 443
78
}
89

10+
export function createConnectorFromIP(ip, tlsOpts = {}, sockOpts = {}) {
11+
const undiciConnect = buildConnector(tlsOpts)
12+
13+
return async (options, callback) => {
14+
let { protocol, hostname, port } = options;
15+
16+
return undiciConnect({
17+
...options,
18+
httpSocket: await createSocketFromHostname(
19+
hostname,
20+
resolvePort(protocol, port),
21+
ip,
22+
sockOpts
23+
)
24+
}, callback);
25+
};
26+
}
27+
28+
export function createRandomStickyConnector(cidr, tlsOpts, options) {
29+
const { bits, ...sockOpts } = options;
30+
const ip = generateRandomIP(cidr, bits);
31+
return createConnectorFromIP(ip, tlsOpts, sockOpts);
32+
}
33+
934
export function createRandomConnector(cidr, tlsOpts = {}, sockOpts = {}) {
1035
const undiciConnect = buildConnector(tlsOpts)
1136

@@ -24,7 +49,18 @@ export function createRandomConnector(cidr, tlsOpts = {}, sockOpts = {}) {
2449
};
2550
}
2651

52+
export function dispatcherFromIP(ip, options = {}) {
53+
const { connect, ...rest } = options
54+
return new Agent({ ...rest, connect: createConnectorFromIP(ip, connect, rest) })
55+
}
56+
57+
export function randomStickyDispatcher(cidr, options = {}) {
58+
const { connect, ...rest } = options
59+
return new Agent({ ...rest, connect: createRandomStickyConnector(cidr, connect, rest) })
60+
}
61+
2762
export function randomDispatcher(cidr, options = {}) {
2863
const { connect, ...rest } = options
2964
return new Agent({ ...rest, connect: createRandomConnector(cidr, connect, rest) })
30-
}
65+
}
66+

index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
1+
import { generateRandomIP } from './ip.js'
2+
13
export * as tcp from './socket.js'
24
export * from './dispatcher.js'
5+
export const ip = { random: generateRandomIP };

ip.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ function generateRandomIPArray({ bytes, available }, count = available) {
2323
}
2424

2525
export function generateRandomIP(cidr, count) {
26-
const addr = ip.fromByteArray(
26+
return ip.fromByteArray(
2727
generateRandomIPArray(parseCIDR(cidr), count)
28-
);
29-
30-
return { addr: addr.toString(), kind: addr.kind() };
28+
).toString();
3129
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "freebind",
3-
"version": "0.1.2",
3+
"version": "0.2.0",
44
"description": "bind sockets to random IP addresses from specified prefixes",
55
"keywords": ["anyip", "rate-limit", "socket", "ipv6", "ratelimiting"],
66
"type": "module",

socket.js

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import sys from 'syscall-napi'
2-
import ipaddr from 'ipaddr.js'
2+
import ip from 'ipaddr.js'
33
import { Socket } from 'node:net'
44
import dns from 'node:dns/promises'
55
import { strict as assert } from 'node:assert'
@@ -39,9 +39,10 @@ async function enableFreebind(fd) {
3939

4040
// todo: createDgram
4141
export async function createSocket(host, port, localAddress, connectOptions) {
42-
const addrFamily = ipaddr.parse(host).kind()
43-
if (connectOptions.strict !== false)
44-
assert(addrFamily == ipaddr.parse(localAddress).kind())
42+
const addrFamily = ip.parse(host).kind()
43+
if (connectOptions.strict !== false) {
44+
assert(addrFamily == ip.parse(localAddress).kind())
45+
}
4546

4647
const fd = await initSocket(addrFamily, 'tcp');
4748
await enableFreebind(fd);
@@ -71,17 +72,28 @@ async function lookup(hostname, family) {
7172
return host;
7273
}
7374

74-
// `bits` defines how many bits to fill from the MSB to the LSB
75-
// needs to be <= length of the prefix
76-
export async function createRandomSocket(hostname, port, localCIDR, options) {
77-
const { bits, strict, ...connectOptions } = options;
78-
const { addr, kind } = generateRandomIP(localCIDR, bits);
75+
export async function createSocketFromHostname(hostname, port, sourceIP, options) {
76+
const { strict, ...connectOptions } = options;
77+
78+
const kind = ip.parse(sourceIP).kind();
7979
const family = ({ 'ipv4': 4, 'ipv6': 6 })[ kind ];
8080

8181
const host = await lookup(hostname, family);
8282
const familyMatching = family === host.family;
83-
if (!familyMatching && strict !== false)
84-
throw 'family mismatch for addr ' + host.address
83+
if (!familyMatching && strict !== false) {
84+
throw 'family mismatch for addr ' + host.address;
85+
}
8586

86-
return await createSocket(host.address, port, addr, { ...connectOptions, strict, familyMatching })
87+
return createSocket(
88+
host.address, port, sourceIP,
89+
{ ...connectOptions, strict, familyMatching }
90+
);
91+
}
92+
93+
// `bits` defines how many bits to fill from the MSB to the LSB
94+
// needs to be <= length of the prefix
95+
export function createRandomSocket(hostname, port, localCIDR, options) {
96+
const { bits, ...rest } = options;
97+
const addr = generateRandomIP(localCIDR, bits);
98+
return createSocketFromHostname(hostname, port, addr, rest);
8799
}

0 commit comments

Comments
 (0)