Skip to content

Commit

Permalink
merge: v0.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
dumbmoron committed May 12, 2024
2 parents 48a6e4d + 13b4c18 commit bdb1100
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 19 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Publish Package to npmjs
on:
release:
types: [published]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
40 changes: 38 additions & 2 deletions dispatcher.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,36 @@
import { createRandomSocket } from './socket.js'
import { generateRandomIP } from './ip.js';
import { createRandomSocket, createSocketFromHostname } from './socket.js'
import { Agent, buildConnector } from 'undici'

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

export function createConnectorFromIP(ip, tlsOpts = {}, sockOpts = {}) {
const undiciConnect = buildConnector(tlsOpts)

return async (options, callback) => {
let { protocol, hostname, port } = options;

return undiciConnect({
...options,
httpSocket: await createSocketFromHostname(
hostname,
resolvePort(protocol, port),
ip,
sockOpts
)
}, callback);
};
}

export function createRandomStickyConnector(cidr, tlsOpts, options) {
const { bits, ...sockOpts } = options;
const ip = generateRandomIP(cidr, bits);
return createConnectorFromIP(ip, tlsOpts, sockOpts);
}

export function createRandomConnector(cidr, tlsOpts = {}, sockOpts = {}) {
const undiciConnect = buildConnector(tlsOpts)

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

export function dispatcherFromIP(ip, options = {}) {
const { connect, ...rest } = options
return new Agent({ ...rest, connect: createConnectorFromIP(ip, connect, rest) })
}

export function randomStickyDispatcher(cidr, options = {}) {
const { connect, ...rest } = options
return new Agent({ ...rest, connect: createRandomStickyConnector(cidr, connect, rest) })
}

export function randomDispatcher(cidr, options = {}) {
const { connect, ...rest } = options
return new Agent({ ...rest, connect: createRandomConnector(cidr, connect, rest) })
}
}

3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
import { generateRandomIP } from './ip.js'

export * as tcp from './socket.js'
export * from './dispatcher.js'
export const ip = { random: generateRandomIP };
6 changes: 2 additions & 4 deletions ip.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ function generateRandomIPArray({ bytes, available }, count = available) {
}

export function generateRandomIP(cidr, count) {
const addr = ip.fromByteArray(
return ip.fromByteArray(
generateRandomIPArray(parseCIDR(cidr), count)
);

return { addr: addr.toString(), kind: addr.kind() };
).toString();
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "freebind",
"version": "0.1.2",
"version": "0.2.0",
"description": "bind sockets to random IP addresses from specified prefixes",
"keywords": ["anyip", "rate-limit", "socket", "ipv6", "ratelimiting"],
"type": "module",
Expand Down
36 changes: 24 additions & 12 deletions socket.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys from 'syscall-napi'
import ipaddr from 'ipaddr.js'
import ip from 'ipaddr.js'
import { Socket } from 'node:net'
import dns from 'node:dns/promises'
import { strict as assert } from 'node:assert'
Expand Down Expand Up @@ -39,9 +39,10 @@ async function enableFreebind(fd) {

// todo: createDgram
export async function createSocket(host, port, localAddress, connectOptions) {
const addrFamily = ipaddr.parse(host).kind()
if (connectOptions.strict !== false)
assert(addrFamily == ipaddr.parse(localAddress).kind())
const addrFamily = ip.parse(host).kind()
if (connectOptions.strict !== false) {
assert(addrFamily == ip.parse(localAddress).kind())
}

const fd = await initSocket(addrFamily, 'tcp');
await enableFreebind(fd);
Expand Down Expand Up @@ -71,17 +72,28 @@ async function lookup(hostname, family) {
return host;
}

// `bits` defines how many bits to fill from the MSB to the LSB
// needs to be <= length of the prefix
export async function createRandomSocket(hostname, port, localCIDR, options) {
const { bits, strict, ...connectOptions } = options;
const { addr, kind } = generateRandomIP(localCIDR, bits);
export async function createSocketFromHostname(hostname, port, sourceIP, options) {
const { strict, ...connectOptions } = options;

const kind = ip.parse(sourceIP).kind();
const family = ({ 'ipv4': 4, 'ipv6': 6 })[ kind ];

const host = await lookup(hostname, family);
const familyMatching = family === host.family;
if (!familyMatching && strict !== false)
throw 'family mismatch for addr ' + host.address
if (!familyMatching && strict !== false) {
throw 'family mismatch for addr ' + host.address;
}

return await createSocket(host.address, port, addr, { ...connectOptions, strict, familyMatching })
return createSocket(
host.address, port, sourceIP,
{ ...connectOptions, strict, familyMatching }
);
}

// `bits` defines how many bits to fill from the MSB to the LSB
// needs to be <= length of the prefix
export function createRandomSocket(hostname, port, localCIDR, options) {
const { bits, ...rest } = options;
const addr = generateRandomIP(localCIDR, bits);
return createSocketFromHostname(hostname, port, addr, rest);
}

0 comments on commit bdb1100

Please sign in to comment.