@push.rocks/smartproxy 24.0.1 → 25.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/certs/cert.pem +18 -17
- package/assets/certs/key.pem +26 -26
- package/changelog.md +23 -0
- package/dist_rust/rustproxy_linux_amd64 +0 -0
- package/dist_rust/rustproxy_linux_arm64 +0 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/models/index.d.ts +1 -1
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +30 -1
- package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.js +5 -2
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +25 -2
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +1 -1
- package/ts/proxies/smart-proxy/models/index.ts +1 -1
- package/ts/proxies/smart-proxy/models/interfaces.ts +33 -1
- package/ts/proxies/smart-proxy/rust-metrics-adapter.ts +4 -1
- package/ts/proxies/smart-proxy/smart-proxy.ts +30 -2
- package/readme.byte-counting-audit.md +0 -169
package/assets/certs/cert.pem
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
-----BEGIN CERTIFICATE-----
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
2
|
+
MIIDQTCCAimgAwIBAgIUJm+igT1AVSuwNzjvqjSF6cysw6MwDQYJKoZIhvcNAQEL
|
|
3
|
+
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI2MDIxMzIyMzI1MloXDTM2MDIx
|
|
4
|
+
MTIyMzI1MlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
|
|
5
|
+
AAOCAQ8AMIIBCgKCAQEAyjitkDd4DdlVk4TfVxKUqdxnJCGj9uyrUPAqR8hB6+bR
|
|
6
|
+
+8rW63ryBNYNRizxOGw41E19ascNuyA98mUF4oqjid1K4VqDiKzv1Uq/3NUunCw/
|
|
7
|
+
rEddR5hCoVkTsBJjzNgBJqncS606v0hfA00cCkpGR+Te7Q/E8T8lApioz1zFQ05Y
|
|
8
|
+
C69oeJHIrJcrIkIFAgmXDgRF0Z4ErUeu+wVOWT267uVAYn5AdFMxCSIBsYtPseqy
|
|
9
|
+
cC5EQ6BCBtsIGitlRgzLRg957ZZa+SF38ao+/ijYmOLHpQT0mFaUyLT7BKgxguGs
|
|
10
|
+
8CHcIxN5Qo27J3sC5ymnrv2uk5DcAOUcxklXUbVCeQIDAQABo4GKMIGHMB0GA1Ud
|
|
11
|
+
DgQWBBShZhz7aX/KhleAfYKvTgyG5ANuDjAfBgNVHSMEGDAWgBShZhz7aX/KhleA
|
|
12
|
+
fYKvTgyG5ANuDjAPBgNVHRMBAf8EBTADAQH/MDQGA1UdEQQtMCuCCWxvY2FsaG9z
|
|
13
|
+
dIIKcHVzaC5yb2Nrc4IMKi5wdXNoLnJvY2tzhwR/AAABMA0GCSqGSIb3DQEBCwUA
|
|
14
|
+
A4IBAQAyUvjUszQp4riqa3CfBFFtjh+7DKNuQPOlYAwSEis4l+YK06Glx4fJBHcx
|
|
15
|
+
eCPhQ/0wnPzi6CZe3vVRXd5fX27nVs+lMQD6Oc47F8OmTU6NXnb/1AcvrycDsP8D
|
|
16
|
+
9Y9qecekbpegrN1W4D46goBAwvrd6Qy0EHi0Z5z02rfyXAdxm0OmdpuWoIMcEgUQ
|
|
17
|
+
YyXIq3zSFE6uoO61WdLvBcXN6iaiSTVy0605WncDe2+UT9MeNq6zi1JD34jsgUrd
|
|
18
|
+
xq0WRUk2C6C4Irkf00Q12rXeL+Jv5OwyrUUZRvz0gLgG02UUbB/6Ca5GYNXniEuI
|
|
19
|
+
Py/EHTqbtjLIs7HxYjQH86FI9fUj
|
|
19
20
|
-----END CERTIFICATE-----
|
package/assets/certs/key.pem
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
-----BEGIN PRIVATE KEY-----
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
2
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDKOK2QN3gN2VWT
|
|
3
|
+
hN9XEpSp3GckIaP27KtQ8CpHyEHr5tH7ytbrevIE1g1GLPE4bDjUTX1qxw27ID3y
|
|
4
|
+
ZQXiiqOJ3UrhWoOIrO/VSr/c1S6cLD+sR11HmEKhWROwEmPM2AEmqdxLrTq/SF8D
|
|
5
|
+
TRwKSkZH5N7tD8TxPyUCmKjPXMVDTlgLr2h4kcislysiQgUCCZcOBEXRngStR677
|
|
6
|
+
BU5ZPbru5UBifkB0UzEJIgGxi0+x6rJwLkRDoEIG2wgaK2VGDMtGD3ntllr5IXfx
|
|
7
|
+
qj7+KNiY4selBPSYVpTItPsEqDGC4azwIdwjE3lCjbsnewLnKaeu/a6TkNwA5RzG
|
|
8
|
+
SVdRtUJ5AgMBAAECggEAEM8piTp9I5yQVxr1RCv+mMiB99BGjHrTij6uawlXxnPJ
|
|
9
|
+
Ol574zbU6Yc/8vh/JB8l0arvzQmHCAoX8B9K4BABZE81X1paYujqJi8ImAMN9Owe
|
|
10
|
+
LlQ/yhjbWAVbJDiBHHjLjrLRpaY8gwQxZqk5FpdiNG1vROIZzypeKZM2PAdke9HA
|
|
11
|
+
PvJtsyfXdEz+jb5EUgaadyn7aquR6y607a8m55y34POLOcssteUOje4GdrTekHK0
|
|
12
|
+
62E+iEnawBjIs7gBzJf0j1XjFNq3aAeLrn8gFCEb+yK7X++8FJ8YjwsqS5V1aMsR
|
|
13
|
+
1PZguW0jCzYHATc2OcIozlvdBriPxy7eX8Y3MFvNMQKBgQD22ReUyKX5TKA/fg3z
|
|
14
|
+
S/QGfYqd4T35jkwK1MaXOuFOBzNyTMT6ZJkbjxPOYPB0uakcfIlva8bI77mE5vRe
|
|
15
|
+
PWYlvitp9Zz3v2kt/WgnwG32ZdVedPjEoi9aitUXmiiIoxdPVAUAgLPFFN65Sr2G
|
|
16
|
+
2NM/vduZcAPUr0UWnFx4dlpo8QKBgQDRuAV44Y+1396511oW4OR8ofWFECMc5uEV
|
|
17
|
+
wQ26EpbilEYhRSBty+1PAK5AcEGybeVtUn9RSmx0Ef1L15wnzP/C886LIzkaig/9
|
|
18
|
+
xs0yudXgOFdBAzYQKnK2lZmSKkzcUFJtifat3E+ZMCo/duhzXpzecg/lVNGh6gcx
|
|
19
|
+
xbtphJCyCQKBgEO8zvvFE8aVgGPr82gQL6aYTLGGXbtdkQBn4xcc0TbYQwXaizMq
|
|
20
|
+
59joKkc30sQ1LnLiudQZfzMklYQi3Gv/7UfuJ3usKqbRn8s+/pXp+ELlLuf8sUdE
|
|
21
|
+
OjpeXptbckQMfRkHtVet+abbU0MFf3zBgza6osg4NNToQ80wmy9zStwBAoGAGLeD
|
|
22
|
+
jZeoBFt6OJT0/TVMOJQuB5y7RrC/Xnz+TSvbtKCdE1a+V7JtKZ5+6wFP/OOO4q+S
|
|
23
|
+
adZHqfZk0Ad9VAOJMUTi1usz07jp4ZMIpC3a0y5QukzSll0qX/KJwvxRSrX8wQQ9
|
|
24
|
+
mogYqYlPsWMmSlKgUmdHEFRK0LZwWqFfUTRaiWECgYEA6KR6KMbqnYn5CglHeD42
|
|
25
|
+
NmOgFYXljRLIxS1coTiWWQZM/nUyx/tSk+MAS7770USHoZhAfh6lmEa/AeKSoLVl
|
|
26
|
+
Su3yzgtKk1/doAtbiWD8TasHAhacwWmzTuZtH5cZUgW3QIVJg6ADi6m8zswqKxIS
|
|
27
|
+
qfU/1N4aHp832v4ggRe/Og0=
|
|
28
28
|
-----END PRIVATE KEY-----
|
package/changelog.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-02-13 - 25.1.0 - feat(metrics)
|
|
4
|
+
add real-time throughput sampling and byte-counting metrics
|
|
5
|
+
|
|
6
|
+
- Add CountingBody wrapper to count HTTP request and response bytes and report them to MetricsCollector.
|
|
7
|
+
- Implement lock-free hot-path byte recording and a cold-path sampling API (sample_all) in MetricsCollector with throughput history and configurable retention (default 3600s).
|
|
8
|
+
- Spawn a background sampling task in RustProxy (configurable sample_interval_ms) and tear it down on stop so throughput trackers are regularly sampled.
|
|
9
|
+
- Instrument passthrough TCP forwarding and socket-relay paths to record per-chunk bytes (lock-free) so long-lived connections contribute to throughput measurements.
|
|
10
|
+
- Wrap HTTP request/response bodies with CountingBody in proxy_service to capture bytes_in/bytes_out and report on body completion; connection_closed handling updated accordingly.
|
|
11
|
+
- Expose recent throughput metrics to the TypeScript adapter (throughputRecentIn/Out) and pass metrics settings from the TS SmartProxy into Rust.
|
|
12
|
+
- Add http-body dependency and update Cargo.toml/Cargo.lock entries for the new body wrapper usage.
|
|
13
|
+
- Add unit tests for MetricsCollector throughput tracking and a new end-to-end throughput test (test.throughput.ts).
|
|
14
|
+
- Update test certificates (assets/certs cert.pem and key.pem) used by TLS tests.
|
|
15
|
+
|
|
16
|
+
## 2026-02-13 - 25.0.0 - BREAKING CHANGE(certs)
|
|
17
|
+
accept a second eventComms argument in certProvisionFunction, add cert provisioning event types, and emit certificate lifecycle events
|
|
18
|
+
|
|
19
|
+
- Breaking API change: certProvisionFunction signature changed from (domain: string) => Promise<TSmartProxyCertProvisionObject> to (domain: string, eventComms: ICertProvisionEventComms) => Promise<TSmartProxyCertProvisionObject>. Custom provisioners must accept (or safely ignore) the new second argument.
|
|
20
|
+
- New types added and exported: ICertProvisionEventComms, ICertificateIssuedEvent, ICertificateFailedEvent.
|
|
21
|
+
- smart-proxy now constructs an eventComms channel that allows provisioners to log/warn/error and set expiry date and source for the issued event.
|
|
22
|
+
- Emits 'certificate-issued' (domain, expiryDate, source, isRenewal?) on successful provisioning and 'certificate-failed' (domain, error, source) on failures.
|
|
23
|
+
- Updated public exports to include the new types so they are available to consumers.
|
|
24
|
+
- Removed readme.byte-counting-audit.md (documentation file deleted).
|
|
25
|
+
|
|
3
26
|
## 2026-02-13 - 24.0.1 - fix(proxy)
|
|
4
27
|
improve proxy robustness: add connect timeouts, graceful shutdown, WebSocket watchdog, and metrics guard
|
|
5
28
|
|
|
Binary file
|
|
Binary file
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartproxy',
|
|
6
|
-
version: '
|
|
6
|
+
version: '25.1.0',
|
|
7
7
|
description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLHFQQUFxUDtDQUNuUSxDQUFBIn0=
|
package/dist_ts/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
export { SmartProxy } from './proxies/smart-proxy/index.js';
|
|
5
5
|
export { SharedRouteManager as RouteManager } from './core/routing/route-manager.js';
|
|
6
6
|
export type { ISmartProxyOptions, IConnectionRecord, IRouteConfig, IRouteMatch, IRouteAction, IRouteTls, IRouteContext } from './proxies/smart-proxy/models/index.js';
|
|
7
|
-
export type { TSmartProxyCertProvisionObject } from './proxies/smart-proxy/models/interfaces.js';
|
|
7
|
+
export type { TSmartProxyCertProvisionObject, ICertProvisionEventComms, ICertificateIssuedEvent, ICertificateFailedEvent } from './proxies/smart-proxy/models/interfaces.js';
|
|
8
8
|
export * from './proxies/smart-proxy/utils/index.js';
|
|
9
9
|
export { SniHandler } from './tls/sni/sni-handler.js';
|
|
10
10
|
export * from './core/models/common-types.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SmartProxy models
|
|
3
3
|
*/
|
|
4
|
-
export type { ISmartProxyOptions, ISmartProxyCertStore, IConnectionRecord, TSmartProxyCertProvisionObject } from './interfaces.js';
|
|
4
|
+
export type { ISmartProxyOptions, ISmartProxyCertStore, IConnectionRecord, TSmartProxyCertProvisionObject, ICertProvisionEventComms, ICertificateIssuedEvent, ICertificateFailedEvent } from './interfaces.js';
|
|
5
5
|
export * from './route-types.js';
|
|
6
6
|
export * from './metrics-types.js';
|
|
@@ -35,6 +35,35 @@ import type { IRouteConfig } from './route-types.js';
|
|
|
35
35
|
* Provision object for static or HTTP-01 certificate
|
|
36
36
|
*/
|
|
37
37
|
export type TSmartProxyCertProvisionObject = plugins.tsclass.network.ICert | 'http01';
|
|
38
|
+
/**
|
|
39
|
+
* Communication channel passed as second argument to certProvisionFunction.
|
|
40
|
+
* Allows the callback to report metadata back to SmartProxy for event emission.
|
|
41
|
+
*/
|
|
42
|
+
export interface ICertProvisionEventComms {
|
|
43
|
+
/** Informational log */
|
|
44
|
+
log: (message: string) => void;
|
|
45
|
+
/** Warning (non-fatal) */
|
|
46
|
+
warn: (message: string) => void;
|
|
47
|
+
/** Error */
|
|
48
|
+
error: (message: string) => void;
|
|
49
|
+
/** Set the certificate expiry date (for the issued event) */
|
|
50
|
+
setExpiryDate: (date: Date) => void;
|
|
51
|
+
/** Set the source/method used for provisioning (e.g. 'smartacme-dns-01') */
|
|
52
|
+
setSource: (source: string) => void;
|
|
53
|
+
}
|
|
54
|
+
/** Payload for 'certificate-issued' and 'certificate-renewed' events */
|
|
55
|
+
export interface ICertificateIssuedEvent {
|
|
56
|
+
domain: string;
|
|
57
|
+
expiryDate?: string;
|
|
58
|
+
source: string;
|
|
59
|
+
isRenewal?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/** Payload for 'certificate-failed' event */
|
|
62
|
+
export interface ICertificateFailedEvent {
|
|
63
|
+
domain: string;
|
|
64
|
+
error: string;
|
|
65
|
+
source: string;
|
|
66
|
+
}
|
|
38
67
|
/**
|
|
39
68
|
* SmartProxy configuration options
|
|
40
69
|
*/
|
|
@@ -115,7 +144,7 @@ export interface ISmartProxyOptions {
|
|
|
115
144
|
* Optional certificate provider callback. Return 'http01' to use HTTP-01 challenges,
|
|
116
145
|
* or a static certificate object for immediate provisioning.
|
|
117
146
|
*/
|
|
118
|
-
certProvisionFunction?: (domain: string) => Promise<TSmartProxyCertProvisionObject>;
|
|
147
|
+
certProvisionFunction?: (domain: string, eventComms: ICertProvisionEventComms) => Promise<TSmartProxyCertProvisionObject>;
|
|
119
148
|
/**
|
|
120
149
|
* Whether to fallback to ACME if custom certificate provision fails.
|
|
121
150
|
* Default: true
|
|
@@ -47,7 +47,10 @@ export class RustMetricsAdapter {
|
|
|
47
47
|
};
|
|
48
48
|
},
|
|
49
49
|
recent: () => {
|
|
50
|
-
return
|
|
50
|
+
return {
|
|
51
|
+
in: this.cache?.throughputRecentInBytesPerSec ?? 0,
|
|
52
|
+
out: this.cache?.throughputRecentOutBytesPerSec ?? 0,
|
|
53
|
+
};
|
|
51
54
|
},
|
|
52
55
|
average: () => {
|
|
53
56
|
return this.throughput.instant();
|
|
@@ -143,4 +146,4 @@ export class RustMetricsAdapter {
|
|
|
143
146
|
}
|
|
144
147
|
}
|
|
145
148
|
}
|
|
146
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
149
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVzdC1tZXRyaWNzLWFkYXB0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L3J1c3QtbWV0cmljcy1hZGFwdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLE9BQU8sa0JBQWtCO0lBTTdCLFlBQVksTUFBdUIsRUFBRSxjQUFjLEdBQUcsSUFBSTtRQUpsRCxVQUFLLEdBQVEsSUFBSSxDQUFDO1FBQ2xCLGNBQVMsR0FBMEMsSUFBSSxDQUFDO1FBc0NoRSxrQ0FBa0M7UUFFM0IsZ0JBQVcsR0FBRztZQUNuQixNQUFNLEVBQUUsR0FBVyxFQUFFO2dCQUNuQixPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsaUJBQWlCLElBQUksQ0FBQyxDQUFDO1lBQzVDLENBQUM7WUFDRCxLQUFLLEVBQUUsR0FBVyxFQUFFO2dCQUNsQixPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsZ0JBQWdCLElBQUksQ0FBQyxDQUFDO1lBQzNDLENBQUM7WUFDRCxPQUFPLEVBQUUsR0FBd0IsRUFBRTtnQkFDakMsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENBQUM7Z0JBQ3pDLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQztvQkFDdkIsS0FBSyxNQUFNLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO3dCQUMzRCxNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRyxFQUFVLENBQUMsaUJBQWlCLElBQUksQ0FBQyxDQUFDLENBQUM7b0JBQ3ZELENBQUM7Z0JBQ0gsQ0FBQztnQkFDRCxPQUFPLE1BQU0sQ0FBQztZQUNoQixDQUFDO1lBQ0QsSUFBSSxFQUFFLEdBQXdCLEVBQUU7Z0JBQzlCLDhDQUE4QztnQkFDOUMsT0FB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
|
|
@@ -326,6 +326,7 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
326
326
|
extendedKeepAliveLifetime: this.settings.extendedKeepAliveLifetime,
|
|
327
327
|
acceptProxyProtocol: this.settings.acceptProxyProtocol,
|
|
328
328
|
sendProxyProtocol: this.settings.sendProxyProtocol,
|
|
329
|
+
metrics: this.settings.metrics,
|
|
329
330
|
};
|
|
330
331
|
}
|
|
331
332
|
/**
|
|
@@ -349,8 +350,18 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
349
350
|
if (provisionedDomains.has(domain))
|
|
350
351
|
continue;
|
|
351
352
|
provisionedDomains.add(domain);
|
|
353
|
+
// Build eventComms channel for this domain
|
|
354
|
+
let expiryDate;
|
|
355
|
+
let source = 'certProvisionFunction';
|
|
356
|
+
const eventComms = {
|
|
357
|
+
log: (msg) => logger.log('info', `[certProvision ${domain}] ${msg}`, { component: 'smart-proxy' }),
|
|
358
|
+
warn: (msg) => logger.log('warn', `[certProvision ${domain}] ${msg}`, { component: 'smart-proxy' }),
|
|
359
|
+
error: (msg) => logger.log('error', `[certProvision ${domain}] ${msg}`, { component: 'smart-proxy' }),
|
|
360
|
+
setExpiryDate: (date) => { expiryDate = date.toISOString(); },
|
|
361
|
+
setSource: (s) => { source = s; },
|
|
362
|
+
};
|
|
352
363
|
try {
|
|
353
|
-
const result = await provisionFn(domain);
|
|
364
|
+
const result = await provisionFn(domain, eventComms);
|
|
354
365
|
if (result === 'http01') {
|
|
355
366
|
// Callback wants HTTP-01 for this domain — trigger Rust ACME explicitly
|
|
356
367
|
if (route.name) {
|
|
@@ -379,10 +390,22 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
379
390
|
logger.log('warn', `certStore.save() failed for ${domain}: ${storeErr.message}`, { component: 'smart-proxy' });
|
|
380
391
|
}
|
|
381
392
|
}
|
|
393
|
+
// Emit certificate-issued event
|
|
394
|
+
this.emit('certificate-issued', {
|
|
395
|
+
domain,
|
|
396
|
+
expiryDate: expiryDate || (certObj.validUntil ? new Date(certObj.validUntil).toISOString() : undefined),
|
|
397
|
+
source,
|
|
398
|
+
});
|
|
382
399
|
}
|
|
383
400
|
}
|
|
384
401
|
catch (err) {
|
|
385
402
|
logger.log('warn', `certProvisionFunction failed for ${domain}: ${err.message}`, { component: 'smart-proxy' });
|
|
403
|
+
// Emit certificate-failed event
|
|
404
|
+
this.emit('certificate-failed', {
|
|
405
|
+
domain,
|
|
406
|
+
error: err.message,
|
|
407
|
+
source,
|
|
408
|
+
});
|
|
386
409
|
// Fallback to ACME if enabled and route has a name
|
|
387
410
|
if (this.settings.certProvisionFallbackToAcme !== false && route.name) {
|
|
388
411
|
try {
|
|
@@ -442,4 +465,4 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
442
465
|
return validDomainRegex.test(domain);
|
|
443
466
|
}
|
|
444
467
|
}
|
|
445
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnQtcHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L3NtYXJ0LXByb3h5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRXBELDBCQUEwQjtBQUMxQixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDekQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDNUQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDakUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFL0QsbUJBQW1CO0FBQ25CLE9BQU8sRUFBRSxrQkFBa0IsSUFBSSxZQUFZLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUN6RixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDNUQsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDL0UsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBT3pDOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sT0FBTyxVQUFXLFNBQVEsT0FBTyxDQUFDLFlBQVk7SUFXbEQsWUFBWSxXQUErQjtRQUN6QyxLQUFLLEVBQUUsQ0FBQztRQU5GLHdCQUFtQixHQUErQixJQUFJLENBQUM7UUFHdkQsYUFBUSxHQUFHLEtBQUssQ0FBQztRQUt2QixpQkFBaUI7UUFDakIsSUFBSSxDQUFDLFFBQVEsR0FBRztZQUNkLEdBQUcsV0FBVztZQUNkLGtCQUFrQixFQUFFLFdBQVcsQ0FBQyxrQkFBa0IsSUFBSSxNQUFNO1lBQzVELGFBQWEsRUFBRSxXQUFXLENBQUMsYUFBYSxJQUFJLE9BQU87WUFD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
|
|
468
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnQtcHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L3NtYXJ0LXByb3h5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFDNUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRXBELDBCQUEwQjtBQUMxQixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDekQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDNUQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDakUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFL0QsbUJBQW1CO0FBQ25CLE9BQU8sRUFBRSxrQkFBa0IsSUFBSSxZQUFZLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUN6RixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDNUQsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDL0UsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBT3pDOzs7Ozs7Ozs7R0FTRztBQUNILE1BQU0sT0FBTyxVQUFXLFNBQVEsT0FBTyxDQUFDLFlBQVk7SUFXbEQsWUFBWSxXQUErQjtRQUN6QyxLQUFLLEVBQUUsQ0FBQztRQU5GLHdCQUFtQixHQUErQixJQUFJLENBQUM7UUFHdkQsYUFBUSxHQUFHLEtBQUssQ0FBQztRQUt2QixpQkFBaUI7UUFDakIsSUFBSSxDQUFDLFFBQVEsR0FBRztZQUNkLEdBQUcsV0FBVztZQUNkLGtCQUFrQixFQUFFLFdBQVcsQ0FBQyxrQkFBa0IsSUFBSSxNQUFNO1lBQzVELGFBQWEsRUFBRSxXQUFXLENBQUMsYUFBYSxJQUFJLE9BQU87WUFD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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartproxy",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "25.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartproxy',
|
|
6
|
-
version: '
|
|
6
|
+
version: '25.1.0',
|
|
7
7
|
description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
|
|
8
8
|
}
|
package/ts/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { SharedRouteManager as RouteManager } from './core/routing/route-manager
|
|
|
8
8
|
|
|
9
9
|
// Export smart-proxy models
|
|
10
10
|
export type { ISmartProxyOptions, IConnectionRecord, IRouteConfig, IRouteMatch, IRouteAction, IRouteTls, IRouteContext } from './proxies/smart-proxy/models/index.js';
|
|
11
|
-
export type { TSmartProxyCertProvisionObject } from './proxies/smart-proxy/models/interfaces.js';
|
|
11
|
+
export type { TSmartProxyCertProvisionObject, ICertProvisionEventComms, ICertificateIssuedEvent, ICertificateFailedEvent } from './proxies/smart-proxy/models/interfaces.js';
|
|
12
12
|
export * from './proxies/smart-proxy/utils/index.js';
|
|
13
13
|
|
|
14
14
|
// Original: export * from './smartproxy/classes.pp.snihandler.js'
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* SmartProxy models
|
|
3
3
|
*/
|
|
4
4
|
// Export everything except IAcmeOptions from interfaces
|
|
5
|
-
export type { ISmartProxyOptions, ISmartProxyCertStore, IConnectionRecord, TSmartProxyCertProvisionObject } from './interfaces.js';
|
|
5
|
+
export type { ISmartProxyOptions, ISmartProxyCertStore, IConnectionRecord, TSmartProxyCertProvisionObject, ICertProvisionEventComms, ICertificateIssuedEvent, ICertificateFailedEvent } from './interfaces.js';
|
|
6
6
|
export * from './route-types.js';
|
|
7
7
|
export * from './metrics-types.js';
|
|
@@ -34,6 +34,38 @@ import type { IRouteConfig } from './route-types.js';
|
|
|
34
34
|
*/
|
|
35
35
|
export type TSmartProxyCertProvisionObject = plugins.tsclass.network.ICert | 'http01';
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Communication channel passed as second argument to certProvisionFunction.
|
|
39
|
+
* Allows the callback to report metadata back to SmartProxy for event emission.
|
|
40
|
+
*/
|
|
41
|
+
export interface ICertProvisionEventComms {
|
|
42
|
+
/** Informational log */
|
|
43
|
+
log: (message: string) => void;
|
|
44
|
+
/** Warning (non-fatal) */
|
|
45
|
+
warn: (message: string) => void;
|
|
46
|
+
/** Error */
|
|
47
|
+
error: (message: string) => void;
|
|
48
|
+
/** Set the certificate expiry date (for the issued event) */
|
|
49
|
+
setExpiryDate: (date: Date) => void;
|
|
50
|
+
/** Set the source/method used for provisioning (e.g. 'smartacme-dns-01') */
|
|
51
|
+
setSource: (source: string) => void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Payload for 'certificate-issued' and 'certificate-renewed' events */
|
|
55
|
+
export interface ICertificateIssuedEvent {
|
|
56
|
+
domain: string;
|
|
57
|
+
expiryDate?: string; // ISO 8601
|
|
58
|
+
source: string; // e.g. 'certProvisionFunction', 'smartacme-dns-01'
|
|
59
|
+
isRenewal?: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Payload for 'certificate-failed' event */
|
|
63
|
+
export interface ICertificateFailedEvent {
|
|
64
|
+
domain: string;
|
|
65
|
+
error: string;
|
|
66
|
+
source: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
37
69
|
// Legacy options and type checking functions have been removed
|
|
38
70
|
|
|
39
71
|
/**
|
|
@@ -140,7 +172,7 @@ export interface ISmartProxyOptions {
|
|
|
140
172
|
* Optional certificate provider callback. Return 'http01' to use HTTP-01 challenges,
|
|
141
173
|
* or a static certificate object for immediate provisioning.
|
|
142
174
|
*/
|
|
143
|
-
certProvisionFunction?: (domain: string) => Promise<TSmartProxyCertProvisionObject>;
|
|
175
|
+
certProvisionFunction?: (domain: string, eventComms: ICertProvisionEventComms) => Promise<TSmartProxyCertProvisionObject>;
|
|
144
176
|
|
|
145
177
|
/**
|
|
146
178
|
* Whether to fallback to ACME if custom certificate provision fails.
|
|
@@ -89,7 +89,10 @@ export class RustMetricsAdapter implements IMetrics {
|
|
|
89
89
|
};
|
|
90
90
|
},
|
|
91
91
|
recent: (): IThroughputData => {
|
|
92
|
-
return
|
|
92
|
+
return {
|
|
93
|
+
in: this.cache?.throughputRecentInBytesPerSec ?? 0,
|
|
94
|
+
out: this.cache?.throughputRecentOutBytesPerSec ?? 0,
|
|
95
|
+
};
|
|
93
96
|
},
|
|
94
97
|
average: (): IThroughputData => {
|
|
95
98
|
return this.throughput.instant();
|
|
@@ -14,7 +14,7 @@ import { generateDefaultCertificate } from './utils/default-cert-generator.js';
|
|
|
14
14
|
import { Mutex } from './utils/mutex.js';
|
|
15
15
|
|
|
16
16
|
// Types
|
|
17
|
-
import type { ISmartProxyOptions, TSmartProxyCertProvisionObject, IAcmeOptions } from './models/interfaces.js';
|
|
17
|
+
import type { ISmartProxyOptions, TSmartProxyCertProvisionObject, IAcmeOptions, ICertProvisionEventComms, ICertificateIssuedEvent, ICertificateFailedEvent } from './models/interfaces.js';
|
|
18
18
|
import type { IRouteConfig } from './models/route-types.js';
|
|
19
19
|
import type { IMetrics } from './models/metrics-types.js';
|
|
20
20
|
|
|
@@ -396,6 +396,7 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
396
396
|
extendedKeepAliveLifetime: this.settings.extendedKeepAliveLifetime,
|
|
397
397
|
acceptProxyProtocol: this.settings.acceptProxyProtocol,
|
|
398
398
|
sendProxyProtocol: this.settings.sendProxyProtocol,
|
|
399
|
+
metrics: this.settings.metrics,
|
|
399
400
|
};
|
|
400
401
|
}
|
|
401
402
|
|
|
@@ -420,8 +421,21 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
420
421
|
for (const domain of certDomains) {
|
|
421
422
|
if (provisionedDomains.has(domain)) continue;
|
|
422
423
|
provisionedDomains.add(domain);
|
|
424
|
+
|
|
425
|
+
// Build eventComms channel for this domain
|
|
426
|
+
let expiryDate: string | undefined;
|
|
427
|
+
let source = 'certProvisionFunction';
|
|
428
|
+
|
|
429
|
+
const eventComms: ICertProvisionEventComms = {
|
|
430
|
+
log: (msg) => logger.log('info', `[certProvision ${domain}] ${msg}`, { component: 'smart-proxy' }),
|
|
431
|
+
warn: (msg) => logger.log('warn', `[certProvision ${domain}] ${msg}`, { component: 'smart-proxy' }),
|
|
432
|
+
error: (msg) => logger.log('error', `[certProvision ${domain}] ${msg}`, { component: 'smart-proxy' }),
|
|
433
|
+
setExpiryDate: (date) => { expiryDate = date.toISOString(); },
|
|
434
|
+
setSource: (s) => { source = s; },
|
|
435
|
+
};
|
|
436
|
+
|
|
423
437
|
try {
|
|
424
|
-
const result: TSmartProxyCertProvisionObject = await provisionFn(domain);
|
|
438
|
+
const result: TSmartProxyCertProvisionObject = await provisionFn(domain, eventComms);
|
|
425
439
|
|
|
426
440
|
if (result === 'http01') {
|
|
427
441
|
// Callback wants HTTP-01 for this domain — trigger Rust ACME explicitly
|
|
@@ -455,10 +469,24 @@ export class SmartProxy extends plugins.EventEmitter {
|
|
|
455
469
|
logger.log('warn', `certStore.save() failed for ${domain}: ${storeErr.message}`, { component: 'smart-proxy' });
|
|
456
470
|
}
|
|
457
471
|
}
|
|
472
|
+
|
|
473
|
+
// Emit certificate-issued event
|
|
474
|
+
this.emit('certificate-issued', {
|
|
475
|
+
domain,
|
|
476
|
+
expiryDate: expiryDate || (certObj.validUntil ? new Date(certObj.validUntil).toISOString() : undefined),
|
|
477
|
+
source,
|
|
478
|
+
} satisfies ICertificateIssuedEvent);
|
|
458
479
|
}
|
|
459
480
|
} catch (err: any) {
|
|
460
481
|
logger.log('warn', `certProvisionFunction failed for ${domain}: ${err.message}`, { component: 'smart-proxy' });
|
|
461
482
|
|
|
483
|
+
// Emit certificate-failed event
|
|
484
|
+
this.emit('certificate-failed', {
|
|
485
|
+
domain,
|
|
486
|
+
error: err.message,
|
|
487
|
+
source,
|
|
488
|
+
} satisfies ICertificateFailedEvent);
|
|
489
|
+
|
|
462
490
|
// Fallback to ACME if enabled and route has a name
|
|
463
491
|
if (this.settings.certProvisionFallbackToAcme !== false && route.name) {
|
|
464
492
|
try {
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
# SmartProxy Byte Counting Audit Report
|
|
2
|
-
|
|
3
|
-
## Executive Summary
|
|
4
|
-
|
|
5
|
-
After a comprehensive audit of the SmartProxy codebase, I can confirm that **byte counting is implemented correctly** with no instances of double counting. Each byte transferred through the proxy is counted exactly once in each direction.
|
|
6
|
-
|
|
7
|
-
## Byte Counting Implementation
|
|
8
|
-
|
|
9
|
-
### 1. Core Tracking Mechanisms
|
|
10
|
-
|
|
11
|
-
SmartProxy uses two complementary tracking systems:
|
|
12
|
-
|
|
13
|
-
1. **Connection Records** (`IConnectionRecord`):
|
|
14
|
-
- `bytesReceived`: Total bytes received from client
|
|
15
|
-
- `bytesSent`: Total bytes sent to client
|
|
16
|
-
|
|
17
|
-
2. **MetricsCollector**:
|
|
18
|
-
- Global throughput tracking via `ThroughputTracker`
|
|
19
|
-
- Per-connection byte tracking for route/IP metrics
|
|
20
|
-
- Called via `recordBytes(connectionId, bytesIn, bytesOut)`
|
|
21
|
-
|
|
22
|
-
### 2. Where Bytes Are Counted
|
|
23
|
-
|
|
24
|
-
Bytes are counted in only two files:
|
|
25
|
-
|
|
26
|
-
#### a) `route-connection-handler.ts`
|
|
27
|
-
- **Line 351**: TLS alert bytes when no SNI is provided
|
|
28
|
-
- **Lines 1286-1301**: Data forwarding callbacks in `setupBidirectionalForwarding()`
|
|
29
|
-
|
|
30
|
-
#### b) `http-proxy-bridge.ts`
|
|
31
|
-
- **Line 127**: Initial TLS chunk for HttpProxy connections
|
|
32
|
-
- **Lines 142-154**: Data forwarding callbacks in `setupBidirectionalForwarding()`
|
|
33
|
-
|
|
34
|
-
## Connection Flow Analysis
|
|
35
|
-
|
|
36
|
-
### 1. Direct TCP Connection (No TLS)
|
|
37
|
-
|
|
38
|
-
```
|
|
39
|
-
Client → SmartProxy → Target Server
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
1. Connection arrives at `RouteConnectionHandler.handleConnection()`
|
|
43
|
-
2. For non-TLS ports, immediately routes via `routeConnection()`
|
|
44
|
-
3. `setupDirectConnection()` creates target connection
|
|
45
|
-
4. `setupBidirectionalForwarding()` handles all data transfer:
|
|
46
|
-
- `onClientData`: `bytesReceived += chunk.length` + `recordBytes(chunk.length, 0)`
|
|
47
|
-
- `onServerData`: `bytesSent += chunk.length` + `recordBytes(0, chunk.length)`
|
|
48
|
-
|
|
49
|
-
**Result**: ✅ Each byte counted exactly once
|
|
50
|
-
|
|
51
|
-
### 2. TLS Passthrough Connection
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
Client (TLS) → SmartProxy → Target Server (TLS)
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
1. Connection waits for initial data to detect TLS
|
|
58
|
-
2. TLS handshake detected, SNI extracted
|
|
59
|
-
3. Route matched, `setupDirectConnection()` called
|
|
60
|
-
4. Initial chunk stored in `pendingData` (NOT counted yet)
|
|
61
|
-
5. On target connect, `pendingData` written to target (still not counted)
|
|
62
|
-
6. `setupBidirectionalForwarding()` counts ALL bytes including initial chunk
|
|
63
|
-
|
|
64
|
-
**Result**: ✅ Each byte counted exactly once
|
|
65
|
-
|
|
66
|
-
### 3. TLS Termination via HttpProxy
|
|
67
|
-
|
|
68
|
-
```
|
|
69
|
-
Client (TLS) → SmartProxy → HttpProxy (localhost) → Target Server
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
1. TLS connection detected with `tls.mode = "terminate"`
|
|
73
|
-
2. `forwardToHttpProxy()` called:
|
|
74
|
-
- Initial chunk: `bytesReceived += chunk.length` + `recordBytes(chunk.length, 0)`
|
|
75
|
-
3. Proxy connection created to HttpProxy on localhost
|
|
76
|
-
4. `setupBidirectionalForwarding()` handles subsequent data
|
|
77
|
-
|
|
78
|
-
**Result**: ✅ Each byte counted exactly once
|
|
79
|
-
|
|
80
|
-
### 4. HTTP Connection via HttpProxy
|
|
81
|
-
|
|
82
|
-
```
|
|
83
|
-
Client (HTTP) → SmartProxy → HttpProxy (localhost) → Target Server
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
1. Connection on configured HTTP port (`useHttpProxy` ports)
|
|
87
|
-
2. Same flow as TLS termination
|
|
88
|
-
3. All byte counting identical to TLS termination
|
|
89
|
-
|
|
90
|
-
**Result**: ✅ Each byte counted exactly once
|
|
91
|
-
|
|
92
|
-
### 5. NFTables Forwarding
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
Client → [Kernel NFTables] → Target Server
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
1. Connection detected, route matched with `forwardingEngine: 'nftables'`
|
|
99
|
-
2. Connection marked as `usingNetworkProxy = true`
|
|
100
|
-
3. NO application-level forwarding (kernel handles packet routing)
|
|
101
|
-
4. NO byte counting in application layer
|
|
102
|
-
|
|
103
|
-
**Result**: ✅ No counting (correct - kernel handles everything)
|
|
104
|
-
|
|
105
|
-
## Special Cases
|
|
106
|
-
|
|
107
|
-
### PROXY Protocol
|
|
108
|
-
- PROXY protocol headers sent to backend servers are NOT counted in client metrics
|
|
109
|
-
- Only actual client data is counted
|
|
110
|
-
- **Correct behavior**: Protocol overhead is not client data
|
|
111
|
-
|
|
112
|
-
### TLS Alerts
|
|
113
|
-
- TLS alerts (e.g., for missing SNI) are counted as sent bytes
|
|
114
|
-
- **Correct behavior**: Alerts are actual data sent to the client
|
|
115
|
-
|
|
116
|
-
### Initial Chunks
|
|
117
|
-
- **Direct connections**: Stored in `pendingData`, counted when forwarded
|
|
118
|
-
- **HttpProxy connections**: Counted immediately upon receipt
|
|
119
|
-
- **Both approaches**: Count each byte exactly once
|
|
120
|
-
|
|
121
|
-
## Verification Methodology
|
|
122
|
-
|
|
123
|
-
1. **Code Analysis**: Searched for all instances of:
|
|
124
|
-
- `bytesReceived +=` and `bytesSent +=`
|
|
125
|
-
- `recordBytes()` calls
|
|
126
|
-
- Data forwarding implementations
|
|
127
|
-
|
|
128
|
-
2. **Flow Tracing**: Followed data path for each connection type from entry to exit
|
|
129
|
-
|
|
130
|
-
3. **Handler Review**: Examined all forwarding handlers to ensure no additional counting
|
|
131
|
-
|
|
132
|
-
## Findings
|
|
133
|
-
|
|
134
|
-
### ✅ No Double Counting Detected
|
|
135
|
-
|
|
136
|
-
- Each byte is counted exactly once in the direction it flows
|
|
137
|
-
- Connection records and metrics are updated consistently
|
|
138
|
-
- No overlapping or duplicate counting logic found
|
|
139
|
-
|
|
140
|
-
### Areas of Excellence
|
|
141
|
-
|
|
142
|
-
1. **Centralized Counting**: All byte counting happens in just two files
|
|
143
|
-
2. **Consistent Pattern**: Uses `setupBidirectionalForwarding()` with callbacks
|
|
144
|
-
3. **Clear Separation**: Forwarding handlers don't interfere with proxy metrics
|
|
145
|
-
|
|
146
|
-
## Recommendations
|
|
147
|
-
|
|
148
|
-
1. **Debug Logging**: Add optional debug logging to verify byte counts in production:
|
|
149
|
-
```typescript
|
|
150
|
-
if (settings.debugByteCount) {
|
|
151
|
-
logger.log('debug', `Bytes counted: ${connectionId} +${bytes} (total: ${record.bytesReceived})`);
|
|
152
|
-
}
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
2. **Unit Tests**: Create specific tests to ensure byte counting accuracy:
|
|
156
|
-
- Test initial chunk handling
|
|
157
|
-
- Test PROXY protocol overhead exclusion
|
|
158
|
-
- Test HttpProxy forwarding accuracy
|
|
159
|
-
|
|
160
|
-
3. **Protocol Overhead Tracking**: Consider separately tracking:
|
|
161
|
-
- PROXY protocol headers
|
|
162
|
-
- TLS handshake bytes
|
|
163
|
-
- HTTP headers vs body
|
|
164
|
-
|
|
165
|
-
4. **NFTables Documentation**: Clearly document that NFTables-forwarded connections are not included in application metrics
|
|
166
|
-
|
|
167
|
-
## Conclusion
|
|
168
|
-
|
|
169
|
-
SmartProxy's byte counting implementation is **robust and accurate**. The design ensures that each byte is counted exactly once, with clear separation between connection tracking and metrics collection. No remediation is required.
|