simplify ipv6-mapped addresses, for easier reading and blocking

Massimo Melina committed Apr 19, 2022 at 18:29 UTC 403b5656b1cd320b9f226f5e3ae9a628ed548d8c
4 files changed +28 -21
server/src/adminApis.ts
+1 -1
@@ -86,7 +86,7 @@ export const adminApis: ApiHandlers = {
86 connectionClosed(conn: Connection) {
87 list.remove(serializeConnection(conn, true))
88 },
89 - connectionUpdated(conn: Connection, change: Partial<Connection>) {
89 + connectionUpdated(conn: Connection, change: Partial<Omit<Connection,'ip'>>) {
90 if (change.ctx) {
91 Object.assign(change, fromCtx(change.ctx))
92 delete change.ctx
server/src/block.ts
+3 -4
@@ -7,8 +7,8 @@ import { Socket } from 'net'
7
8 subscribeConfig({ k: 'block', defaultValue: [] }, (rules: any) => {
9 compileBlock(rules)
10 - for (const { socket } of getConnections())
11 - applyBlock(socket)
10 + for (const { socket, ip } of getConnections())
11 + applyBlock(socket, ip)
12 })
13
14 type BlockFun = (x: string) => boolean
@@ -29,8 +29,7 @@ function compileBlock(rules: any) {
29 }
30 }
31
32 -export function applyBlock(socket: Socket) {
33 - const ip = socket.remoteAddress
32 +export function applyBlock(socket: Socket, ip=socket.remoteAddress) {
33 if (ip && blockFunctions.find(rule => rule(ip)))
34 return socket.destroy()
35 }
server/src/connections.ts
+22 -15
@@ -4,29 +4,36 @@ import { Socket } from 'net'
4 import events from './events'
5 import Koa from 'koa'
6
7 -export interface Connection {
8 - socket: Socket
9 - secure: boolean
10 - started: Date
11 - got: number
12 - sent: number
7 +export class Connection {
8 + readonly started = new Date()
9 + got = 0
10 + sent = 0
11 + alreadyEmitted = false // already communicated to
12 outSpeed?: number
13 ctx?: Koa.Context
15 - alreadyEmitted: boolean // already communicated to
14 + private _cachedIp?: string
15 [rest:symbol]: any // let other modules add extra data, but using symbols to avoid name collision
16 +
17 + constructor(readonly socket: Socket,readonly secure: boolean) {
18 + all.push(this)
19 + socket.on('data', data =>
20 + this.got += data.length )
21 + socket.on('close', () => {
22 + all.splice(all.indexOf(this), 1)
23 + events.emit('connectionClosed', this)
24 + })
25 + }
26 +
27 + get ip() {
28 + return this.ctx?.ip ?? (this._cachedIp = (this._cachedIp ?? this.socket.remoteAddress?.replace(/^::ffff:/,'')))
29 + }
30 }
31
32 +
33 const all: Connection[] = []
34
35 export function newConnection(socket: Socket, secure:boolean=false) {
22 - const conn: Connection = { socket, secure, got: 0, sent: 0, alreadyEmitted: false, started: new Date() }
23 - all.push(conn)
24 - socket.on('data', data =>
25 - conn.got += data.length )
26 - socket.on('close', () => {
27 - all.splice(all.indexOf(conn), 1)
28 - events.emit('connectionClosed', conn)
29 - })
36 + new Connection(socket, secure)
37 }
38
39 export function getConnections(): Readonly<typeof all> {
server/src/middlewares.ts
+2 -1
@@ -92,6 +92,7 @@ export const serveGuiAndSharedFiles: Koa.Middleware = async (ctx, next) => {
92
93 let proxyDetected = false
94 export const someSecurity: Koa.Middleware = async (ctx, next) => {
95 + ctx.request.ip = ctx.ip.replace(/^::ffff:/,'') // simplify ipv6-mapped addresses
96 try {
97 let proxy = ctx.get('X-Forwarded-For')
98 // we have some dev-proxies to ignore
@@ -99,7 +100,7 @@ export const someSecurity: Koa.Middleware = async (ctx, next) => {
100 proxy = ''
101 if (dirTraversal(decodeURI(ctx.path)))
102 return ctx.status = 418
102 - if (applyBlock(ctx.socket))
103 + if (applyBlock(ctx.socket, ctx.ip))
104 return
105 proxyDetected ||= proxy > ''
106 ctx.state.proxiedFor = proxy