@push.rocks/smartproxy 19.3.2 → 19.3.3

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.
Files changed (313) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/forwarding/factory/forwarding-factory.js +29 -1
  3. package/dist_ts/http/index.d.ts +1 -3
  4. package/dist_ts/http/index.js +4 -10
  5. package/dist_ts/http/models/http-types.d.ts +4 -91
  6. package/dist_ts/http/models/http-types.js +5 -60
  7. package/dist_ts/http/router/proxy-router.d.ts +1 -1
  8. package/dist_ts/http/router/route-router.d.ts +1 -1
  9. package/dist_ts/index.d.ts +9 -7
  10. package/dist_ts/index.js +10 -7
  11. package/dist_ts/proxies/{network-proxy → http-proxy}/certificate-manager.d.ts +2 -2
  12. package/dist_ts/proxies/{network-proxy → http-proxy}/certificate-manager.js +1 -1
  13. package/dist_ts/proxies/{network-proxy → http-proxy}/connection-pool.d.ts +2 -2
  14. package/dist_ts/proxies/http-proxy/connection-pool.js +210 -0
  15. package/dist_ts/proxies/http-proxy/context-creator.js +108 -0
  16. package/dist_ts/proxies/{network-proxy → http-proxy}/function-cache.js +1 -1
  17. package/dist_ts/proxies/http-proxy/handlers/index.d.ts +5 -0
  18. package/dist_ts/proxies/http-proxy/handlers/index.js +6 -0
  19. package/dist_ts/proxies/http-proxy/handlers/redirect-handler.d.ts +18 -0
  20. package/dist_ts/proxies/http-proxy/handlers/redirect-handler.js +78 -0
  21. package/dist_ts/proxies/http-proxy/handlers/static-handler.d.ts +19 -0
  22. package/dist_ts/proxies/http-proxy/handlers/static-handler.js +203 -0
  23. package/dist_ts/proxies/{network-proxy/network-proxy.d.ts → http-proxy/http-proxy.d.ts} +10 -9
  24. package/dist_ts/proxies/{network-proxy/network-proxy.js → http-proxy/http-proxy.js} +13 -12
  25. package/dist_ts/proxies/{network-proxy → http-proxy}/http-request-handler.js +1 -1
  26. package/dist_ts/proxies/http-proxy/http2-request-handler.js +201 -0
  27. package/dist_ts/proxies/{network-proxy → http-proxy}/index.d.ts +2 -2
  28. package/dist_ts/proxies/http-proxy/index.js +12 -0
  29. package/dist_ts/proxies/http-proxy/models/http-types.d.ts +119 -0
  30. package/dist_ts/proxies/http-proxy/models/http-types.js +112 -0
  31. package/dist_ts/proxies/http-proxy/models/index.d.ts +5 -0
  32. package/dist_ts/proxies/http-proxy/models/index.js +6 -0
  33. package/dist_ts/proxies/{network-proxy → http-proxy}/models/types.d.ts +2 -2
  34. package/dist_ts/proxies/http-proxy/models/types.js +276 -0
  35. package/dist_ts/proxies/{network-proxy → http-proxy}/request-handler.d.ts +3 -3
  36. package/dist_ts/proxies/{network-proxy → http-proxy}/request-handler.js +2 -2
  37. package/dist_ts/proxies/http-proxy/security-manager.js +255 -0
  38. package/dist_ts/proxies/{network-proxy → http-proxy}/websocket-handler.d.ts +3 -3
  39. package/dist_ts/proxies/{network-proxy → http-proxy}/websocket-handler.js +2 -2
  40. package/dist_ts/proxies/index.d.ts +5 -5
  41. package/dist_ts/proxies/index.js +5 -5
  42. package/dist_ts/proxies/smart-proxy/certificate-manager.d.ts +4 -4
  43. package/dist_ts/proxies/smart-proxy/certificate-manager.js +11 -11
  44. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +41 -0
  45. package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +121 -0
  46. package/dist_ts/proxies/smart-proxy/index.d.ts +2 -1
  47. package/dist_ts/proxies/smart-proxy/index.js +4 -2
  48. package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +2 -2
  49. package/dist_ts/proxies/smart-proxy/port-manager.js +3 -3
  50. package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +3 -3
  51. package/dist_ts/proxies/smart-proxy/route-connection-handler.js +24 -265
  52. package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +1 -1
  53. package/dist_ts/proxies/smart-proxy/smart-proxy.js +25 -25
  54. package/dist_ts/routing/index.d.ts +5 -0
  55. package/dist_ts/routing/index.js +8 -0
  56. package/dist_ts/routing/models/http-types.d.ts +6 -0
  57. package/dist_ts/routing/models/http-types.js +7 -0
  58. package/dist_ts/routing/router/index.d.ts +8 -0
  59. package/dist_ts/routing/router/index.js +7 -0
  60. package/dist_ts/{classes.router.d.ts → routing/router/proxy-router.d.ts} +14 -11
  61. package/dist_ts/{classes.router.js → routing/router/proxy-router.js} +2 -2
  62. package/dist_ts/routing/router/route-router.d.ts +108 -0
  63. package/dist_ts/routing/router/route-router.js +393 -0
  64. package/package.json +1 -1
  65. package/readme.md +12 -12
  66. package/readme.plan.md +152 -257
  67. package/ts/00_commitinfo_data.ts +1 -1
  68. package/ts/forwarding/factory/forwarding-factory.ts +28 -0
  69. package/ts/index.ts +13 -9
  70. package/ts/proxies/{network-proxy → http-proxy}/certificate-manager.ts +2 -2
  71. package/ts/proxies/{network-proxy → http-proxy}/connection-pool.ts +2 -2
  72. package/ts/proxies/http-proxy/handlers/index.ts +6 -0
  73. package/ts/proxies/http-proxy/handlers/redirect-handler.ts +105 -0
  74. package/ts/proxies/http-proxy/handlers/static-handler.ts +251 -0
  75. package/ts/proxies/{network-proxy/network-proxy.ts → http-proxy/http-proxy.ts} +15 -14
  76. package/ts/proxies/{network-proxy → http-proxy}/index.ts +3 -3
  77. package/ts/proxies/http-proxy/models/http-types.ts +165 -0
  78. package/ts/proxies/http-proxy/models/index.ts +5 -0
  79. package/ts/proxies/{network-proxy → http-proxy}/models/types.ts +2 -2
  80. package/ts/proxies/{network-proxy → http-proxy}/request-handler.ts +3 -3
  81. package/ts/proxies/{network-proxy → http-proxy}/websocket-handler.ts +3 -3
  82. package/ts/proxies/index.ts +7 -7
  83. package/ts/proxies/smart-proxy/certificate-manager.ts +10 -10
  84. package/ts/proxies/smart-proxy/{network-proxy-bridge.ts → http-proxy-bridge.ts} +44 -44
  85. package/ts/proxies/smart-proxy/index.ts +4 -1
  86. package/ts/proxies/smart-proxy/models/interfaces.ts +3 -3
  87. package/ts/proxies/smart-proxy/port-manager.ts +2 -2
  88. package/ts/proxies/smart-proxy/route-connection-handler.ts +23 -307
  89. package/ts/proxies/smart-proxy/smart-proxy.ts +25 -25
  90. package/ts/routing/index.ts +9 -0
  91. package/ts/routing/models/http-types.ts +6 -0
  92. package/ts/{http → routing}/router/proxy-router.ts +1 -1
  93. package/ts/{http → routing}/router/route-router.ts +1 -1
  94. package/dist_ts/certificate/acme/acme-factory.d.ts +0 -17
  95. package/dist_ts/certificate/acme/acme-factory.js +0 -40
  96. package/dist_ts/certificate/acme/challenge-handler.d.ts +0 -44
  97. package/dist_ts/certificate/acme/challenge-handler.js +0 -92
  98. package/dist_ts/certificate/acme/index.d.ts +0 -4
  99. package/dist_ts/certificate/acme/index.js +0 -5
  100. package/dist_ts/certificate/certificate-manager.d.ts +0 -150
  101. package/dist_ts/certificate/certificate-manager.js +0 -505
  102. package/dist_ts/certificate/events/certificate-events.d.ts +0 -33
  103. package/dist_ts/certificate/events/certificate-events.js +0 -38
  104. package/dist_ts/certificate/events/simplified-events.d.ts +0 -56
  105. package/dist_ts/certificate/events/simplified-events.js +0 -13
  106. package/dist_ts/certificate/index.d.ts +0 -30
  107. package/dist_ts/certificate/index.js +0 -37
  108. package/dist_ts/certificate/models/certificate-errors.d.ts +0 -69
  109. package/dist_ts/certificate/models/certificate-errors.js +0 -141
  110. package/dist_ts/certificate/models/certificate-strategy.d.ts +0 -60
  111. package/dist_ts/certificate/models/certificate-strategy.js +0 -73
  112. package/dist_ts/certificate/models/certificate-types.d.ts +0 -97
  113. package/dist_ts/certificate/models/certificate-types.js +0 -2
  114. package/dist_ts/certificate/providers/cert-provisioner.d.ts +0 -119
  115. package/dist_ts/certificate/providers/cert-provisioner.js +0 -422
  116. package/dist_ts/certificate/providers/index.d.ts +0 -4
  117. package/dist_ts/certificate/providers/index.js +0 -5
  118. package/dist_ts/certificate/simplified-certificate-manager.d.ts +0 -150
  119. package/dist_ts/certificate/simplified-certificate-manager.js +0 -501
  120. package/dist_ts/certificate/storage/file-storage.d.ts +0 -66
  121. package/dist_ts/certificate/storage/file-storage.js +0 -194
  122. package/dist_ts/certificate/storage/index.d.ts +0 -4
  123. package/dist_ts/certificate/storage/index.js +0 -5
  124. package/dist_ts/certificate/utils/certificate-helpers.d.ts +0 -17
  125. package/dist_ts/certificate/utils/certificate-helpers.js +0 -45
  126. package/dist_ts/classes.iptablesproxy.d.ts +0 -112
  127. package/dist_ts/classes.iptablesproxy.js +0 -765
  128. package/dist_ts/classes.networkproxy.d.ts +0 -243
  129. package/dist_ts/classes.networkproxy.js +0 -1424
  130. package/dist_ts/classes.nftablesproxy.d.ts +0 -219
  131. package/dist_ts/classes.nftablesproxy.js +0 -1542
  132. package/dist_ts/classes.port80handler.d.ts +0 -215
  133. package/dist_ts/classes.port80handler.js +0 -736
  134. package/dist_ts/classes.portproxy.d.ts +0 -171
  135. package/dist_ts/classes.portproxy.js +0 -1802
  136. package/dist_ts/classes.pp.acmemanager.d.ts +0 -34
  137. package/dist_ts/classes.pp.acmemanager.js +0 -123
  138. package/dist_ts/classes.pp.connectionhandler.d.ts +0 -39
  139. package/dist_ts/classes.pp.connectionhandler.js +0 -754
  140. package/dist_ts/classes.pp.connectionmanager.d.ts +0 -78
  141. package/dist_ts/classes.pp.connectionmanager.js +0 -378
  142. package/dist_ts/classes.pp.domainconfigmanager.d.ts +0 -55
  143. package/dist_ts/classes.pp.domainconfigmanager.js +0 -103
  144. package/dist_ts/classes.pp.interfaces.d.ts +0 -133
  145. package/dist_ts/classes.pp.interfaces.js +0 -2
  146. package/dist_ts/classes.pp.networkproxybridge.d.ts +0 -57
  147. package/dist_ts/classes.pp.networkproxybridge.js +0 -306
  148. package/dist_ts/classes.pp.portproxy.d.ts +0 -64
  149. package/dist_ts/classes.pp.portproxy.js +0 -567
  150. package/dist_ts/classes.pp.portrangemanager.d.ts +0 -56
  151. package/dist_ts/classes.pp.portrangemanager.js +0 -179
  152. package/dist_ts/classes.pp.securitymanager.d.ts +0 -47
  153. package/dist_ts/classes.pp.securitymanager.js +0 -126
  154. package/dist_ts/classes.pp.snihandler.d.ts +0 -153
  155. package/dist_ts/classes.pp.snihandler.js +0 -1053
  156. package/dist_ts/classes.pp.timeoutmanager.d.ts +0 -47
  157. package/dist_ts/classes.pp.timeoutmanager.js +0 -154
  158. package/dist_ts/classes.pp.tlsalert.d.ts +0 -149
  159. package/dist_ts/classes.pp.tlsalert.js +0 -225
  160. package/dist_ts/classes.pp.tlsmanager.d.ts +0 -57
  161. package/dist_ts/classes.pp.tlsmanager.js +0 -132
  162. package/dist_ts/classes.snihandler.d.ts +0 -198
  163. package/dist_ts/classes.snihandler.js +0 -1210
  164. package/dist_ts/classes.sslredirect.d.ts +0 -8
  165. package/dist_ts/classes.sslredirect.js +0 -28
  166. package/dist_ts/common/acmeFactory.d.ts +0 -9
  167. package/dist_ts/common/acmeFactory.js +0 -20
  168. package/dist_ts/common/port80-adapter.d.ts +0 -11
  169. package/dist_ts/common/port80-adapter.js +0 -87
  170. package/dist_ts/examples/forwarding-example.d.ts +0 -1
  171. package/dist_ts/examples/forwarding-example.js +0 -96
  172. package/dist_ts/forwarding/config/domain-config.d.ts +0 -12
  173. package/dist_ts/forwarding/config/domain-config.js +0 -12
  174. package/dist_ts/forwarding/config/domain-manager.d.ts +0 -86
  175. package/dist_ts/forwarding/config/domain-manager.js +0 -242
  176. package/dist_ts/helpers.certificates.d.ts +0 -5
  177. package/dist_ts/helpers.certificates.js +0 -23
  178. package/dist_ts/http/port80/acme-interfaces.d.ts +0 -108
  179. package/dist_ts/http/port80/acme-interfaces.js +0 -51
  180. package/dist_ts/http/port80/challenge-responder.d.ts +0 -53
  181. package/dist_ts/http/port80/challenge-responder.js +0 -203
  182. package/dist_ts/http/port80/index.d.ts +0 -6
  183. package/dist_ts/http/port80/index.js +0 -9
  184. package/dist_ts/http/port80/port80-handler.d.ts +0 -136
  185. package/dist_ts/http/port80/port80-handler.js +0 -592
  186. package/dist_ts/http/redirects/index.d.ts +0 -4
  187. package/dist_ts/http/redirects/index.js +0 -5
  188. package/dist_ts/networkproxy/classes.np.certificatemanager.d.ts +0 -77
  189. package/dist_ts/networkproxy/classes.np.certificatemanager.js +0 -372
  190. package/dist_ts/networkproxy/classes.np.connectionpool.d.ts +0 -47
  191. package/dist_ts/networkproxy/classes.np.connectionpool.js +0 -210
  192. package/dist_ts/networkproxy/classes.np.networkproxy.d.ts +0 -118
  193. package/dist_ts/networkproxy/classes.np.networkproxy.js +0 -387
  194. package/dist_ts/networkproxy/classes.np.requesthandler.d.ts +0 -56
  195. package/dist_ts/networkproxy/classes.np.requesthandler.js +0 -393
  196. package/dist_ts/networkproxy/classes.np.types.d.ts +0 -83
  197. package/dist_ts/networkproxy/classes.np.types.js +0 -35
  198. package/dist_ts/networkproxy/classes.np.websockethandler.d.ts +0 -38
  199. package/dist_ts/networkproxy/classes.np.websockethandler.js +0 -188
  200. package/dist_ts/networkproxy/index.d.ts +0 -1
  201. package/dist_ts/networkproxy/index.js +0 -4
  202. package/dist_ts/nfttablesproxy/classes.nftablesproxy.d.ts +0 -219
  203. package/dist_ts/nfttablesproxy/classes.nftablesproxy.js +0 -1542
  204. package/dist_ts/port80handler/classes.port80handler.d.ts +0 -10
  205. package/dist_ts/port80handler/classes.port80handler.js +0 -16
  206. package/dist_ts/proxies/network-proxy/connection-pool.js +0 -210
  207. package/dist_ts/proxies/network-proxy/context-creator.js +0 -108
  208. package/dist_ts/proxies/network-proxy/http2-request-handler.js +0 -201
  209. package/dist_ts/proxies/network-proxy/index.js +0 -12
  210. package/dist_ts/proxies/network-proxy/models/index.d.ts +0 -4
  211. package/dist_ts/proxies/network-proxy/models/index.js +0 -5
  212. package/dist_ts/proxies/network-proxy/models/types.js +0 -276
  213. package/dist_ts/proxies/network-proxy/security-manager.js +0 -255
  214. package/dist_ts/proxies/network-proxy/simplified-certificate-bridge.d.ts +0 -48
  215. package/dist_ts/proxies/network-proxy/simplified-certificate-bridge.js +0 -76
  216. package/dist_ts/proxies/smart-proxy/connection-handler.d.ts +0 -39
  217. package/dist_ts/proxies/smart-proxy/connection-handler.js +0 -894
  218. package/dist_ts/proxies/smart-proxy/domain-config-manager.d.ts +0 -110
  219. package/dist_ts/proxies/smart-proxy/domain-config-manager.js +0 -386
  220. package/dist_ts/proxies/smart-proxy/legacy-smart-proxy.d.ts +0 -168
  221. package/dist_ts/proxies/smart-proxy/legacy-smart-proxy.js +0 -642
  222. package/dist_ts/proxies/smart-proxy/models/simplified-smartproxy-config.d.ts +0 -65
  223. package/dist_ts/proxies/smart-proxy/models/simplified-smartproxy-config.js +0 -31
  224. package/dist_ts/proxies/smart-proxy/models/smartproxy-options.d.ts +0 -102
  225. package/dist_ts/proxies/smart-proxy/models/smartproxy-options.js +0 -73
  226. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.d.ts +0 -41
  227. package/dist_ts/proxies/smart-proxy/network-proxy-bridge.js +0 -121
  228. package/dist_ts/proxies/smart-proxy/port-range-manager.d.ts +0 -56
  229. package/dist_ts/proxies/smart-proxy/port-range-manager.js +0 -176
  230. package/dist_ts/proxies/smart-proxy/route-helpers/index.d.ts +0 -9
  231. package/dist_ts/proxies/smart-proxy/route-helpers/index.js +0 -11
  232. package/dist_ts/proxies/smart-proxy/route-helpers.d.ts +0 -7
  233. package/dist_ts/proxies/smart-proxy/route-helpers.js +0 -9
  234. package/dist_ts/proxies/smart-proxy/simplified-smart-proxy.d.ts +0 -41
  235. package/dist_ts/proxies/smart-proxy/simplified-smart-proxy.js +0 -132
  236. package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.d.ts +0 -51
  237. package/dist_ts/proxies/smart-proxy/utils/route-migration-utils.js +0 -124
  238. package/dist_ts/redirect/classes.redirect.d.ts +0 -96
  239. package/dist_ts/redirect/classes.redirect.js +0 -194
  240. package/dist_ts/smartproxy/classes.pp.certprovisioner.d.ts +0 -54
  241. package/dist_ts/smartproxy/classes.pp.certprovisioner.js +0 -179
  242. package/dist_ts/smartproxy/classes.pp.connectionhandler.d.ts +0 -39
  243. package/dist_ts/smartproxy/classes.pp.connectionhandler.js +0 -894
  244. package/dist_ts/smartproxy/classes.pp.connectionmanager.d.ts +0 -78
  245. package/dist_ts/smartproxy/classes.pp.connectionmanager.js +0 -378
  246. package/dist_ts/smartproxy/classes.pp.domainconfigmanager.d.ts +0 -94
  247. package/dist_ts/smartproxy/classes.pp.domainconfigmanager.js +0 -255
  248. package/dist_ts/smartproxy/classes.pp.interfaces.d.ts +0 -103
  249. package/dist_ts/smartproxy/classes.pp.interfaces.js +0 -2
  250. package/dist_ts/smartproxy/classes.pp.networkproxybridge.d.ts +0 -62
  251. package/dist_ts/smartproxy/classes.pp.networkproxybridge.js +0 -316
  252. package/dist_ts/smartproxy/classes.pp.portrangemanager.d.ts +0 -56
  253. package/dist_ts/smartproxy/classes.pp.portrangemanager.js +0 -176
  254. package/dist_ts/smartproxy/classes.pp.securitymanager.d.ts +0 -64
  255. package/dist_ts/smartproxy/classes.pp.securitymanager.js +0 -149
  256. package/dist_ts/smartproxy/classes.pp.snihandler.d.ts +0 -153
  257. package/dist_ts/smartproxy/classes.pp.snihandler.js +0 -1053
  258. package/dist_ts/smartproxy/classes.pp.timeoutmanager.d.ts +0 -47
  259. package/dist_ts/smartproxy/classes.pp.timeoutmanager.js +0 -154
  260. package/dist_ts/smartproxy/classes.pp.tlsalert.d.ts +0 -149
  261. package/dist_ts/smartproxy/classes.pp.tlsalert.js +0 -225
  262. package/dist_ts/smartproxy/classes.pp.tlsmanager.d.ts +0 -57
  263. package/dist_ts/smartproxy/classes.pp.tlsmanager.js +0 -132
  264. package/dist_ts/smartproxy/classes.smartproxy.d.ts +0 -63
  265. package/dist_ts/smartproxy/classes.smartproxy.js +0 -521
  266. package/dist_ts/smartproxy/forwarding/domain-config.d.ts +0 -12
  267. package/dist_ts/smartproxy/forwarding/domain-config.js +0 -12
  268. package/dist_ts/smartproxy/forwarding/domain-manager.d.ts +0 -86
  269. package/dist_ts/smartproxy/forwarding/domain-manager.js +0 -241
  270. package/dist_ts/smartproxy/forwarding/forwarding.factory.d.ts +0 -24
  271. package/dist_ts/smartproxy/forwarding/forwarding.factory.js +0 -137
  272. package/dist_ts/smartproxy/forwarding/forwarding.handler.d.ts +0 -55
  273. package/dist_ts/smartproxy/forwarding/forwarding.handler.js +0 -94
  274. package/dist_ts/smartproxy/forwarding/http.handler.d.ts +0 -25
  275. package/dist_ts/smartproxy/forwarding/http.handler.js +0 -123
  276. package/dist_ts/smartproxy/forwarding/https-passthrough.handler.d.ts +0 -24
  277. package/dist_ts/smartproxy/forwarding/https-passthrough.handler.js +0 -154
  278. package/dist_ts/smartproxy/forwarding/https-terminate-to-http.handler.d.ts +0 -36
  279. package/dist_ts/smartproxy/forwarding/https-terminate-to-http.handler.js +0 -229
  280. package/dist_ts/smartproxy/forwarding/https-terminate-to-https.handler.d.ts +0 -35
  281. package/dist_ts/smartproxy/forwarding/https-terminate-to-https.handler.js +0 -254
  282. package/dist_ts/smartproxy/forwarding/index.d.ts +0 -16
  283. package/dist_ts/smartproxy/forwarding/index.js +0 -23
  284. package/dist_ts/smartproxy/types/forwarding.types.d.ts +0 -104
  285. package/dist_ts/smartproxy/types/forwarding.types.js +0 -50
  286. package/dist_ts/smartproxy.classes.networkproxy.d.ts +0 -31
  287. package/dist_ts/smartproxy.classes.networkproxy.js +0 -305
  288. package/dist_ts/smartproxy.classes.router.d.ts +0 -13
  289. package/dist_ts/smartproxy.classes.router.js +0 -33
  290. package/dist_ts/smartproxy.classes.sslredirect.d.ts +0 -8
  291. package/dist_ts/smartproxy.classes.sslredirect.js +0 -28
  292. package/dist_ts/smartproxy.helpers.certificates.d.ts +0 -5
  293. package/dist_ts/smartproxy.helpers.certificates.js +0 -23
  294. package/dist_ts/smartproxy.plugins.d.ts +0 -18
  295. package/dist_ts/smartproxy.plugins.js +0 -23
  296. package/dist_ts/smartproxy.portproxy.d.ts +0 -26
  297. package/dist_ts/smartproxy.portproxy.js +0 -295
  298. package/ts/http/index.ts +0 -16
  299. package/ts/http/models/http-types.ts +0 -108
  300. package/ts/http/redirects/index.ts +0 -3
  301. package/ts/proxies/network-proxy/models/index.ts +0 -4
  302. package/ts/redirect/classes.redirect.ts +0 -295
  303. /package/dist_ts/proxies/{network-proxy → http-proxy}/context-creator.d.ts +0 -0
  304. /package/dist_ts/proxies/{network-proxy → http-proxy}/function-cache.d.ts +0 -0
  305. /package/dist_ts/proxies/{network-proxy → http-proxy}/http-request-handler.d.ts +0 -0
  306. /package/dist_ts/proxies/{network-proxy → http-proxy}/http2-request-handler.d.ts +0 -0
  307. /package/dist_ts/proxies/{network-proxy → http-proxy}/security-manager.d.ts +0 -0
  308. /package/ts/proxies/{network-proxy → http-proxy}/context-creator.ts +0 -0
  309. /package/ts/proxies/{network-proxy → http-proxy}/function-cache.ts +0 -0
  310. /package/ts/proxies/{network-proxy → http-proxy}/http-request-handler.ts +0 -0
  311. /package/ts/proxies/{network-proxy → http-proxy}/http2-request-handler.ts +0 -0
  312. /package/ts/proxies/{network-proxy → http-proxy}/security-manager.ts +0 -0
  313. /package/ts/{http → routing}/router/index.ts +0 -0
@@ -1,1542 +0,0 @@
1
- import { exec, execSync } from 'child_process';
2
- import { promisify } from 'util';
3
- import * as fs from 'fs';
4
- import * as path from 'path';
5
- import * as os from 'os';
6
- const execAsync = promisify(exec);
7
- /**
8
- * Custom error classes for better error handling
9
- */
10
- export class NftBaseError extends Error {
11
- constructor(message) {
12
- super(message);
13
- this.name = 'NftBaseError';
14
- }
15
- }
16
- export class NftValidationError extends NftBaseError {
17
- constructor(message) {
18
- super(message);
19
- this.name = 'NftValidationError';
20
- }
21
- }
22
- export class NftExecutionError extends NftBaseError {
23
- constructor(message) {
24
- super(message);
25
- this.name = 'NftExecutionError';
26
- }
27
- }
28
- export class NftResourceError extends NftBaseError {
29
- constructor(message) {
30
- super(message);
31
- this.name = 'NftResourceError';
32
- }
33
- }
34
- /**
35
- * NfTablesProxy sets up nftables NAT rules to forward TCP traffic.
36
- * Enhanced with multi-port support, IPv6, connection tracking, metrics,
37
- * and more advanced features.
38
- */
39
- export class NfTablesProxy {
40
- static { this.NFT_CMD = 'nft'; }
41
- constructor(settings) {
42
- this.rules = [];
43
- this.ipSets = new Map(); // Store IP sets for tracking
44
- // Validate inputs to prevent command injection
45
- this.validateSettings(settings);
46
- // Set default settings
47
- this.settings = {
48
- ...settings,
49
- toHost: settings.toHost || 'localhost',
50
- protocol: settings.protocol || 'tcp',
51
- enableLogging: settings.enableLogging !== undefined ? settings.enableLogging : false,
52
- ipv6Support: settings.ipv6Support !== undefined ? settings.ipv6Support : false,
53
- tableName: settings.tableName || 'portproxy',
54
- logFormat: settings.logFormat || 'plain',
55
- useIPSets: settings.useIPSets !== undefined ? settings.useIPSets : true,
56
- maxRetries: settings.maxRetries || 3,
57
- retryDelayMs: settings.retryDelayMs || 1000,
58
- useAdvancedNAT: settings.useAdvancedNAT !== undefined ? settings.useAdvancedNAT : false,
59
- };
60
- // Generate a unique identifier for the rules added by this instance
61
- this.ruleTag = `NfTablesProxy:${Date.now()}:${Math.random().toString(36).substr(2, 5)}`;
62
- // Set table name
63
- this.tableName = this.settings.tableName || 'portproxy';
64
- // Create a temp file path for batch operations
65
- this.tempFilePath = path.join(os.tmpdir(), `nft-rules-${Date.now()}.nft`);
66
- // Register cleanup handlers if deleteOnExit is true
67
- if (this.settings.deleteOnExit) {
68
- const cleanup = () => {
69
- try {
70
- this.stopSync();
71
- }
72
- catch (err) {
73
- this.log('error', 'Error cleaning nftables rules on exit:', { error: err.message });
74
- }
75
- };
76
- process.on('exit', cleanup);
77
- process.on('SIGINT', () => {
78
- cleanup();
79
- process.exit();
80
- });
81
- process.on('SIGTERM', () => {
82
- cleanup();
83
- process.exit();
84
- });
85
- }
86
- }
87
- /**
88
- * Validates settings to prevent command injection and ensure valid values
89
- */
90
- validateSettings(settings) {
91
- // Validate port numbers
92
- const validatePorts = (port) => {
93
- if (Array.isArray(port)) {
94
- port.forEach(p => validatePorts(p));
95
- return;
96
- }
97
- if (typeof port === 'number') {
98
- if (port < 1 || port > 65535) {
99
- throw new NftValidationError(`Invalid port number: ${port}`);
100
- }
101
- }
102
- else if (typeof port === 'object') {
103
- if (port.from < 1 || port.from > 65535 || port.to < 1 || port.to > 65535 || port.from > port.to) {
104
- throw new NftValidationError(`Invalid port range: ${port.from}-${port.to}`);
105
- }
106
- }
107
- };
108
- validatePorts(settings.fromPort);
109
- validatePorts(settings.toPort);
110
- // Define regex patterns for validation
111
- const ipRegex = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))?$/;
112
- const ipv6Regex = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$/;
113
- // Validate IP addresses
114
- const validateIPs = (ips) => {
115
- if (!ips)
116
- return;
117
- for (const ip of ips) {
118
- if (!ipRegex.test(ip) && !ipv6Regex.test(ip)) {
119
- throw new NftValidationError(`Invalid IP address format: ${ip}`);
120
- }
121
- }
122
- };
123
- validateIPs(settings.allowedSourceIPs);
124
- validateIPs(settings.bannedSourceIPs);
125
- // Validate toHost - only allow hostnames or IPs
126
- if (settings.toHost) {
127
- const hostRegex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
128
- if (!hostRegex.test(settings.toHost) && !ipRegex.test(settings.toHost) && !ipv6Regex.test(settings.toHost)) {
129
- throw new NftValidationError(`Invalid host format: ${settings.toHost}`);
130
- }
131
- }
132
- // Validate table name to prevent command injection
133
- if (settings.tableName) {
134
- const tableNameRegex = /^[a-zA-Z0-9_]+$/;
135
- if (!tableNameRegex.test(settings.tableName)) {
136
- throw new NftValidationError(`Invalid table name: ${settings.tableName}. Only alphanumeric characters and underscores are allowed.`);
137
- }
138
- }
139
- // Validate QoS settings if enabled
140
- if (settings.qos?.enabled) {
141
- if (settings.qos.maxRate) {
142
- const rateRegex = /^[0-9]+[kKmMgG]?bps$/;
143
- if (!rateRegex.test(settings.qos.maxRate)) {
144
- throw new NftValidationError(`Invalid rate format: ${settings.qos.maxRate}. Use format like "10mbps", "1gbps", etc.`);
145
- }
146
- }
147
- if (settings.qos.priority !== undefined) {
148
- if (settings.qos.priority < 1 || settings.qos.priority > 10 || !Number.isInteger(settings.qos.priority)) {
149
- throw new NftValidationError(`Invalid priority: ${settings.qos.priority}. Must be an integer between 1 and 10.`);
150
- }
151
- }
152
- }
153
- }
154
- /**
155
- * Normalizes port specifications into an array of port ranges
156
- */
157
- normalizePortSpec(portSpec) {
158
- const result = [];
159
- if (Array.isArray(portSpec)) {
160
- // If it's an array, process each element
161
- for (const spec of portSpec) {
162
- result.push(...this.normalizePortSpec(spec));
163
- }
164
- }
165
- else if (typeof portSpec === 'number') {
166
- // Single port becomes a range with the same start and end
167
- result.push({ from: portSpec, to: portSpec });
168
- }
169
- else {
170
- // Already a range
171
- result.push(portSpec);
172
- }
173
- return result;
174
- }
175
- /**
176
- * Execute a command with retry capability
177
- */
178
- async executeWithRetry(command, maxRetries = 3, retryDelayMs = 1000) {
179
- let lastError;
180
- for (let i = 0; i < maxRetries; i++) {
181
- try {
182
- const { stdout } = await execAsync(command);
183
- return stdout;
184
- }
185
- catch (err) {
186
- lastError = err;
187
- this.log('warn', `Command failed (attempt ${i + 1}/${maxRetries}): ${command}`, { error: err.message });
188
- // Wait before retry, unless it's the last attempt
189
- if (i < maxRetries - 1) {
190
- await new Promise(resolve => setTimeout(resolve, retryDelayMs));
191
- }
192
- }
193
- }
194
- throw new NftExecutionError(`Failed after ${maxRetries} attempts: ${lastError?.message || 'Unknown error'}`);
195
- }
196
- /**
197
- * Execute system command synchronously with multiple attempts
198
- */
199
- executeWithRetrySync(command, maxRetries = 3, retryDelayMs = 1000) {
200
- let lastError;
201
- for (let i = 0; i < maxRetries; i++) {
202
- try {
203
- return execSync(command).toString();
204
- }
205
- catch (err) {
206
- lastError = err;
207
- this.log('warn', `Command failed (attempt ${i + 1}/${maxRetries}): ${command}`, { error: err.message });
208
- // Wait before retry, unless it's the last attempt
209
- if (i < maxRetries - 1) {
210
- // A naive sleep in sync context
211
- const waitUntil = Date.now() + retryDelayMs;
212
- while (Date.now() < waitUntil) {
213
- // busy wait - not great, but this is a fallback method
214
- }
215
- }
216
- }
217
- }
218
- throw new NftExecutionError(`Failed after ${maxRetries} attempts: ${lastError?.message || 'Unknown error'}`);
219
- }
220
- /**
221
- * Checks if nftables is available and the required modules are loaded
222
- */
223
- async checkNftablesAvailability() {
224
- try {
225
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} --version`, this.settings.maxRetries, this.settings.retryDelayMs);
226
- // Check for conntrack support if we're using advanced NAT
227
- if (this.settings.useAdvancedNAT) {
228
- try {
229
- await this.executeWithRetry('lsmod | grep nf_conntrack', this.settings.maxRetries, this.settings.retryDelayMs);
230
- }
231
- catch (err) {
232
- this.log('warn', 'Connection tracking modules might not be loaded, advanced NAT features may not work');
233
- }
234
- }
235
- return true;
236
- }
237
- catch (err) {
238
- this.log('error', `nftables is not available: ${err.message}`);
239
- return false;
240
- }
241
- }
242
- /**
243
- * Creates the necessary tables and chains
244
- */
245
- async setupTablesAndChains(isIpv6 = false) {
246
- const family = isIpv6 ? 'ip6' : 'ip';
247
- try {
248
- // Check if the table already exists
249
- const stdout = await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} list tables ${family}`, this.settings.maxRetries, this.settings.retryDelayMs);
250
- const tableExists = stdout.includes(`table ${family} ${this.tableName}`);
251
- if (!tableExists) {
252
- // Create the table
253
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} add table ${family} ${this.tableName}`, this.settings.maxRetries, this.settings.retryDelayMs);
254
- this.log('info', `Created table ${family} ${this.tableName}`);
255
- // Create the nat chain for the prerouting hook
256
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} add chain ${family} ${this.tableName} nat_prerouting { type nat hook prerouting priority -100 ; }`, this.settings.maxRetries, this.settings.retryDelayMs);
257
- this.log('info', `Created nat_prerouting chain in ${family} ${this.tableName}`);
258
- // Create the nat chain for the postrouting hook if not preserving source IP
259
- if (!this.settings.preserveSourceIP) {
260
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} add chain ${family} ${this.tableName} nat_postrouting { type nat hook postrouting priority 100 ; }`, this.settings.maxRetries, this.settings.retryDelayMs);
261
- this.log('info', `Created nat_postrouting chain in ${family} ${this.tableName}`);
262
- }
263
- // Create the chain for NetworkProxy integration if needed
264
- if (this.settings.netProxyIntegration?.enabled && this.settings.netProxyIntegration.redirectLocalhost) {
265
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} add chain ${family} ${this.tableName} nat_output { type nat hook output priority 0 ; }`, this.settings.maxRetries, this.settings.retryDelayMs);
266
- this.log('info', `Created nat_output chain in ${family} ${this.tableName}`);
267
- }
268
- // Create the QoS chain if needed
269
- if (this.settings.qos?.enabled) {
270
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} add chain ${family} ${this.tableName} qos_forward { type filter hook forward priority 0 ; }`, this.settings.maxRetries, this.settings.retryDelayMs);
271
- this.log('info', `Created QoS forward chain in ${family} ${this.tableName}`);
272
- }
273
- }
274
- else {
275
- this.log('info', `Table ${family} ${this.tableName} already exists, using existing table`);
276
- }
277
- return true;
278
- }
279
- catch (err) {
280
- this.log('error', `Failed to set up tables and chains: ${err.message}`);
281
- return false;
282
- }
283
- }
284
- /**
285
- * Creates IP sets for efficient filtering of large IP lists
286
- */
287
- async createIPSet(family, setName, ips, setType = 'ipv4_addr') {
288
- try {
289
- // Filter IPs based on family
290
- const filteredIPs = ips.filter(ip => {
291
- if (family === 'ip6' && ip.includes(':'))
292
- return true;
293
- if (family === 'ip' && ip.includes('.'))
294
- return true;
295
- return false;
296
- });
297
- if (filteredIPs.length === 0) {
298
- this.log('info', `No IP addresses of type ${setType} to add to set ${setName}`);
299
- return true;
300
- }
301
- // Check if set already exists
302
- try {
303
- const sets = await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} list sets ${family} ${this.tableName}`, this.settings.maxRetries, this.settings.retryDelayMs);
304
- if (sets.includes(`set ${setName} {`)) {
305
- this.log('info', `IP set ${setName} already exists, will add elements`);
306
- }
307
- else {
308
- // Create the set
309
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} add set ${family} ${this.tableName} ${setName} { type ${setType}; }`, this.settings.maxRetries, this.settings.retryDelayMs);
310
- this.log('info', `Created IP set ${setName} for ${family} with type ${setType}`);
311
- }
312
- }
313
- catch (err) {
314
- // Set might not exist yet, create it
315
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} add set ${family} ${this.tableName} ${setName} { type ${setType}; }`, this.settings.maxRetries, this.settings.retryDelayMs);
316
- this.log('info', `Created IP set ${setName} for ${family} with type ${setType}`);
317
- }
318
- // Add IPs to the set in batches to avoid command line length limitations
319
- const batchSize = 100;
320
- for (let i = 0; i < filteredIPs.length; i += batchSize) {
321
- const batch = filteredIPs.slice(i, i + batchSize);
322
- const elements = batch.join(', ');
323
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} add element ${family} ${this.tableName} ${setName} { ${elements} }`, this.settings.maxRetries, this.settings.retryDelayMs);
324
- this.log('info', `Added batch of ${batch.length} IPs to set ${setName}`);
325
- }
326
- // Track the IP set
327
- this.ipSets.set(`${family}:${setName}`, filteredIPs);
328
- return true;
329
- }
330
- catch (err) {
331
- this.log('error', `Failed to create IP set ${setName}: ${err.message}`);
332
- return false;
333
- }
334
- }
335
- /**
336
- * Adds source IP filtering rules, potentially using IP sets for efficiency
337
- */
338
- async addSourceIPFilters(isIpv6 = false) {
339
- if (!this.settings.allowedSourceIPs && !this.settings.bannedSourceIPs) {
340
- return true; // Nothing to do
341
- }
342
- const family = isIpv6 ? 'ip6' : 'ip';
343
- const chain = 'nat_prerouting';
344
- const setType = isIpv6 ? 'ipv6_addr' : 'ipv4_addr';
345
- try {
346
- // Start building the ruleset file content
347
- let rulesetContent = '';
348
- // Using IP sets for more efficient rule processing with large IP lists
349
- if (this.settings.useIPSets) {
350
- // Create sets for banned and allowed IPs if needed
351
- if (this.settings.bannedSourceIPs && this.settings.bannedSourceIPs.length > 0) {
352
- const setName = 'banned_ips';
353
- await this.createIPSet(family, setName, this.settings.bannedSourceIPs, setType);
354
- // Add rule to drop traffic from banned IPs
355
- const rule = `add rule ${family} ${this.tableName} ${chain} ip${isIpv6 ? '6' : ''} saddr @${setName} drop comment "${this.ruleTag}:BANNED_SET"`;
356
- rulesetContent += `${rule}\n`;
357
- this.rules.push({
358
- tableFamily: family,
359
- tableName: this.tableName,
360
- chainName: chain,
361
- ruleContents: rule,
362
- added: false
363
- });
364
- }
365
- if (this.settings.allowedSourceIPs && this.settings.allowedSourceIPs.length > 0) {
366
- const setName = 'allowed_ips';
367
- await this.createIPSet(family, setName, this.settings.allowedSourceIPs, setType);
368
- // Add rule to allow traffic from allowed IPs
369
- const rule = `add rule ${family} ${this.tableName} ${chain} ip${isIpv6 ? '6' : ''} saddr @${setName} ${this.settings.protocol} dport {${this.getAllPorts(this.settings.fromPort)}} accept comment "${this.ruleTag}:ALLOWED_SET"`;
370
- rulesetContent += `${rule}\n`;
371
- this.rules.push({
372
- tableFamily: family,
373
- tableName: this.tableName,
374
- chainName: chain,
375
- ruleContents: rule,
376
- added: false
377
- });
378
- // Add default deny rule for unlisted IPs
379
- const denyRule = `add rule ${family} ${this.tableName} ${chain} ${this.settings.protocol} dport {${this.getAllPorts(this.settings.fromPort)}} drop comment "${this.ruleTag}:DENY_ALL"`;
380
- rulesetContent += `${denyRule}\n`;
381
- this.rules.push({
382
- tableFamily: family,
383
- tableName: this.tableName,
384
- chainName: chain,
385
- ruleContents: denyRule,
386
- added: false
387
- });
388
- }
389
- }
390
- else {
391
- // Traditional approach without IP sets - less efficient for large IP lists
392
- // Ban specific IPs first
393
- if (this.settings.bannedSourceIPs && this.settings.bannedSourceIPs.length > 0) {
394
- for (const ip of this.settings.bannedSourceIPs) {
395
- // Skip IPv4 addresses for IPv6 rules and vice versa
396
- if (isIpv6 && ip.includes('.'))
397
- continue;
398
- if (!isIpv6 && ip.includes(':'))
399
- continue;
400
- const rule = `add rule ${family} ${this.tableName} ${chain} ip${isIpv6 ? '6' : ''} saddr ${ip} drop comment "${this.ruleTag}:BANNED"`;
401
- rulesetContent += `${rule}\n`;
402
- this.rules.push({
403
- tableFamily: family,
404
- tableName: this.tableName,
405
- chainName: chain,
406
- ruleContents: rule,
407
- added: false
408
- });
409
- }
410
- }
411
- // Allow specific IPs
412
- if (this.settings.allowedSourceIPs && this.settings.allowedSourceIPs.length > 0) {
413
- // Add rules to allow specific IPs
414
- for (const ip of this.settings.allowedSourceIPs) {
415
- // Skip IPv4 addresses for IPv6 rules and vice versa
416
- if (isIpv6 && ip.includes('.'))
417
- continue;
418
- if (!isIpv6 && ip.includes(':'))
419
- continue;
420
- const rule = `add rule ${family} ${this.tableName} ${chain} ip${isIpv6 ? '6' : ''} saddr ${ip} ${this.settings.protocol} dport {${this.getAllPorts(this.settings.fromPort)}} accept comment "${this.ruleTag}:ALLOWED"`;
421
- rulesetContent += `${rule}\n`;
422
- this.rules.push({
423
- tableFamily: family,
424
- tableName: this.tableName,
425
- chainName: chain,
426
- ruleContents: rule,
427
- added: false
428
- });
429
- }
430
- // Add default deny rule for unlisted IPs
431
- const denyRule = `add rule ${family} ${this.tableName} ${chain} ${this.settings.protocol} dport {${this.getAllPorts(this.settings.fromPort)}} drop comment "${this.ruleTag}:DENY_ALL"`;
432
- rulesetContent += `${denyRule}\n`;
433
- this.rules.push({
434
- tableFamily: family,
435
- tableName: this.tableName,
436
- chainName: chain,
437
- ruleContents: denyRule,
438
- added: false
439
- });
440
- }
441
- }
442
- // Only write and apply if we have rules to add
443
- if (rulesetContent) {
444
- // Write the ruleset to a temporary file
445
- fs.writeFileSync(this.tempFilePath, rulesetContent);
446
- // Apply the ruleset
447
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} -f ${this.tempFilePath}`, this.settings.maxRetries, this.settings.retryDelayMs);
448
- this.log('info', `Added source IP filter rules for ${family}`);
449
- // Mark rules as added
450
- for (const rule of this.rules) {
451
- if (rule.tableFamily === family && !rule.added) {
452
- rule.added = true;
453
- // Verify the rule was applied
454
- await this.verifyRuleApplication(rule);
455
- }
456
- }
457
- // Remove the temporary file
458
- fs.unlinkSync(this.tempFilePath);
459
- }
460
- return true;
461
- }
462
- catch (err) {
463
- this.log('error', `Failed to add source IP filter rules: ${err.message}`);
464
- // Try to clean up any rules that might have been added
465
- this.rollbackRules();
466
- return false;
467
- }
468
- }
469
- /**
470
- * Gets a comma-separated list of all ports from a port specification
471
- */
472
- getAllPorts(portSpec) {
473
- const portRanges = this.normalizePortSpec(portSpec);
474
- const ports = [];
475
- for (const range of portRanges) {
476
- if (range.from === range.to) {
477
- ports.push(range.from.toString());
478
- }
479
- else {
480
- ports.push(`${range.from}-${range.to}`);
481
- }
482
- }
483
- return ports.join(', ');
484
- }
485
- /**
486
- * Configures advanced NAT with connection tracking
487
- */
488
- async setupAdvancedNAT(isIpv6 = false) {
489
- if (!this.settings.useAdvancedNAT) {
490
- return true; // Skip if not using advanced NAT
491
- }
492
- const family = isIpv6 ? 'ip6' : 'ip';
493
- const preroutingChain = 'nat_prerouting';
494
- try {
495
- // Get the port ranges
496
- const fromPortRanges = this.normalizePortSpec(this.settings.fromPort);
497
- const toPortRanges = this.normalizePortSpec(this.settings.toPort);
498
- let rulesetContent = '';
499
- // Simple case - one-to-one mapping with connection tracking
500
- if (fromPortRanges.length === 1 && toPortRanges.length === 1) {
501
- const fromRange = fromPortRanges[0];
502
- const toRange = toPortRanges[0];
503
- // Single port to single port with connection tracking
504
- if (fromRange.from === fromRange.to && toRange.from === toRange.to) {
505
- const rule = `add rule ${family} ${this.tableName} ${preroutingChain} ${this.settings.protocol} dport ${fromRange.from} ct state new dnat to ${this.settings.toHost}:${toRange.from} comment "${this.ruleTag}:DNAT_CT"`;
506
- rulesetContent += `${rule}\n`;
507
- this.rules.push({
508
- tableFamily: family,
509
- tableName: this.tableName,
510
- chainName: preroutingChain,
511
- ruleContents: rule,
512
- added: false
513
- });
514
- }
515
- // Port range with same size
516
- else if ((fromRange.to - fromRange.from) === (toRange.to - toRange.from)) {
517
- const rule = `add rule ${family} ${this.tableName} ${preroutingChain} ${this.settings.protocol} dport ${fromRange.from}-${fromRange.to} ct state new dnat to ${this.settings.toHost}:${toRange.from}-${toRange.to} comment "${this.ruleTag}:DNAT_RANGE_CT"`;
518
- rulesetContent += `${rule}\n`;
519
- this.rules.push({
520
- tableFamily: family,
521
- tableName: this.tableName,
522
- chainName: preroutingChain,
523
- ruleContents: rule,
524
- added: false
525
- });
526
- }
527
- // Add related and established connection rule for efficient connection handling
528
- const ctRule = `add rule ${family} ${this.tableName} ${preroutingChain} ct state established,related accept comment "${this.ruleTag}:CT_ESTABLISHED"`;
529
- rulesetContent += `${ctRule}\n`;
530
- this.rules.push({
531
- tableFamily: family,
532
- tableName: this.tableName,
533
- chainName: preroutingChain,
534
- ruleContents: ctRule,
535
- added: false
536
- });
537
- // Apply the rules if we have any
538
- if (rulesetContent) {
539
- fs.writeFileSync(this.tempFilePath, rulesetContent);
540
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} -f ${this.tempFilePath}`, this.settings.maxRetries, this.settings.retryDelayMs);
541
- this.log('info', `Added advanced NAT rules for ${family}`);
542
- // Mark rules as added
543
- for (const rule of this.rules) {
544
- if (rule.tableFamily === family && !rule.added) {
545
- rule.added = true;
546
- // Verify the rule was applied
547
- await this.verifyRuleApplication(rule);
548
- }
549
- }
550
- // Remove the temporary file
551
- fs.unlinkSync(this.tempFilePath);
552
- }
553
- }
554
- return true;
555
- }
556
- catch (err) {
557
- this.log('error', `Failed to set up advanced NAT: ${err.message}`);
558
- return false;
559
- }
560
- }
561
- /**
562
- * Adds port forwarding rules
563
- */
564
- async addPortForwardingRules(isIpv6 = false) {
565
- // Skip if using advanced NAT as that already handles the port forwarding
566
- if (this.settings.useAdvancedNAT) {
567
- return true;
568
- }
569
- const family = isIpv6 ? 'ip6' : 'ip';
570
- const preroutingChain = 'nat_prerouting';
571
- const postroutingChain = 'nat_postrouting';
572
- try {
573
- // Normalize port specifications
574
- const fromPortRanges = this.normalizePortSpec(this.settings.fromPort);
575
- const toPortRanges = this.normalizePortSpec(this.settings.toPort);
576
- // Handle the case where fromPort and toPort counts don't match
577
- if (fromPortRanges.length !== toPortRanges.length) {
578
- if (toPortRanges.length === 1) {
579
- // If there's only one toPort, use it for all fromPorts
580
- const singleToRange = toPortRanges[0];
581
- return await this.addPortMappings(family, preroutingChain, postroutingChain, fromPortRanges, singleToRange);
582
- }
583
- else {
584
- throw new NftValidationError('Mismatched port counts: fromPort and toPort arrays must have equal length or toPort must be a single value');
585
- }
586
- }
587
- else {
588
- // Add port mapping rules for each port pair
589
- return await this.addPortPairMappings(family, preroutingChain, postroutingChain, fromPortRanges, toPortRanges);
590
- }
591
- }
592
- catch (err) {
593
- this.log('error', `Failed to add port forwarding rules: ${err.message}`);
594
- return false;
595
- }
596
- }
597
- /**
598
- * Adds port forwarding rules for the case where one toPortRange maps to multiple fromPortRanges
599
- */
600
- async addPortMappings(family, preroutingChain, postroutingChain, fromPortRanges, toPortRange) {
601
- try {
602
- let rulesetContent = '';
603
- // For each from port range, create a mapping to the single to port range
604
- for (const fromRange of fromPortRanges) {
605
- // Simple case: single port to single port
606
- if (fromRange.from === fromRange.to && toPortRange.from === toPortRange.to) {
607
- const rule = `add rule ${family} ${this.tableName} ${preroutingChain} ${this.settings.protocol} dport ${fromRange.from} dnat to ${this.settings.toHost}:${toPortRange.from} comment "${this.ruleTag}:DNAT"`;
608
- rulesetContent += `${rule}\n`;
609
- this.rules.push({
610
- tableFamily: family,
611
- tableName: this.tableName,
612
- chainName: preroutingChain,
613
- ruleContents: rule,
614
- added: false
615
- });
616
- }
617
- // Multiple ports in from range, but only one port in to range
618
- else if (toPortRange.from === toPortRange.to) {
619
- // Map each port in from range to the single to port
620
- for (let p = fromRange.from; p <= fromRange.to; p++) {
621
- const rule = `add rule ${family} ${this.tableName} ${preroutingChain} ${this.settings.protocol} dport ${p} dnat to ${this.settings.toHost}:${toPortRange.from} comment "${this.ruleTag}:DNAT"`;
622
- rulesetContent += `${rule}\n`;
623
- this.rules.push({
624
- tableFamily: family,
625
- tableName: this.tableName,
626
- chainName: preroutingChain,
627
- ruleContents: rule,
628
- added: false
629
- });
630
- }
631
- }
632
- // Port range to port range mapping with modulo distribution
633
- else {
634
- const toRangeSize = toPortRange.to - toPortRange.from + 1;
635
- for (let p = fromRange.from; p <= fromRange.to; p++) {
636
- const offset = (p - fromRange.from) % toRangeSize;
637
- const targetPort = toPortRange.from + offset;
638
- const rule = `add rule ${family} ${this.tableName} ${preroutingChain} ${this.settings.protocol} dport ${p} dnat to ${this.settings.toHost}:${targetPort} comment "${this.ruleTag}:DNAT"`;
639
- rulesetContent += `${rule}\n`;
640
- this.rules.push({
641
- tableFamily: family,
642
- tableName: this.tableName,
643
- chainName: preroutingChain,
644
- ruleContents: rule,
645
- added: false
646
- });
647
- }
648
- }
649
- }
650
- // Add masquerade rule for source NAT if not preserving source IP
651
- if (!this.settings.preserveSourceIP) {
652
- const ports = this.getAllPorts(this.settings.toPort);
653
- const masqRule = `add rule ${family} ${this.tableName} ${postroutingChain} ${this.settings.protocol} daddr ${this.settings.toHost} dport {${ports}} masquerade comment "${this.ruleTag}:MASQ"`;
654
- rulesetContent += `${masqRule}\n`;
655
- this.rules.push({
656
- tableFamily: family,
657
- tableName: this.tableName,
658
- chainName: postroutingChain,
659
- ruleContents: masqRule,
660
- added: false
661
- });
662
- }
663
- // Apply the ruleset if we have any rules
664
- if (rulesetContent) {
665
- // Write to temporary file
666
- fs.writeFileSync(this.tempFilePath, rulesetContent);
667
- // Apply the ruleset
668
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} -f ${this.tempFilePath}`, this.settings.maxRetries, this.settings.retryDelayMs);
669
- this.log('info', `Added port forwarding rules for ${family}`);
670
- // Mark rules as added
671
- for (const rule of this.rules) {
672
- if (rule.tableFamily === family && !rule.added) {
673
- rule.added = true;
674
- // Verify the rule was applied
675
- await this.verifyRuleApplication(rule);
676
- }
677
- }
678
- // Remove temporary file
679
- fs.unlinkSync(this.tempFilePath);
680
- }
681
- return true;
682
- }
683
- catch (err) {
684
- this.log('error', `Failed to add port mappings: ${err.message}`);
685
- return false;
686
- }
687
- }
688
- /**
689
- * Adds port forwarding rules for pairs of fromPortRanges and toPortRanges
690
- */
691
- async addPortPairMappings(family, preroutingChain, postroutingChain, fromPortRanges, toPortRanges) {
692
- try {
693
- let rulesetContent = '';
694
- // Process each fromPort and toPort pair
695
- for (let i = 0; i < fromPortRanges.length; i++) {
696
- const fromRange = fromPortRanges[i];
697
- const toRange = toPortRanges[i];
698
- // Simple case: single port to single port
699
- if (fromRange.from === fromRange.to && toRange.from === toRange.to) {
700
- const rule = `add rule ${family} ${this.tableName} ${preroutingChain} ${this.settings.protocol} dport ${fromRange.from} dnat to ${this.settings.toHost}:${toRange.from} comment "${this.ruleTag}:DNAT"`;
701
- rulesetContent += `${rule}\n`;
702
- this.rules.push({
703
- tableFamily: family,
704
- tableName: this.tableName,
705
- chainName: preroutingChain,
706
- ruleContents: rule,
707
- added: false
708
- });
709
- }
710
- // Port range with equal size - can use direct mapping
711
- else if ((fromRange.to - fromRange.from) === (toRange.to - toRange.from)) {
712
- const rule = `add rule ${family} ${this.tableName} ${preroutingChain} ${this.settings.protocol} dport ${fromRange.from}-${fromRange.to} dnat to ${this.settings.toHost}:${toRange.from}-${toRange.to} comment "${this.ruleTag}:DNAT_RANGE"`;
713
- rulesetContent += `${rule}\n`;
714
- this.rules.push({
715
- tableFamily: family,
716
- tableName: this.tableName,
717
- chainName: preroutingChain,
718
- ruleContents: rule,
719
- added: false
720
- });
721
- }
722
- // Unequal port ranges - need to map individually
723
- else {
724
- const toRangeSize = toRange.to - toRange.from + 1;
725
- for (let p = fromRange.from; p <= fromRange.to; p++) {
726
- const offset = (p - fromRange.from) % toRangeSize;
727
- const targetPort = toRange.from + offset;
728
- const rule = `add rule ${family} ${this.tableName} ${preroutingChain} ${this.settings.protocol} dport ${p} dnat to ${this.settings.toHost}:${targetPort} comment "${this.ruleTag}:DNAT_INDIVIDUAL"`;
729
- rulesetContent += `${rule}\n`;
730
- this.rules.push({
731
- tableFamily: family,
732
- tableName: this.tableName,
733
- chainName: preroutingChain,
734
- ruleContents: rule,
735
- added: false
736
- });
737
- }
738
- }
739
- // Add masquerade rule for this port range if not preserving source IP
740
- if (!this.settings.preserveSourceIP) {
741
- const masqRule = `add rule ${family} ${this.tableName} ${postroutingChain} ${this.settings.protocol} daddr ${this.settings.toHost} dport ${toRange.from}-${toRange.to} masquerade comment "${this.ruleTag}:MASQ"`;
742
- rulesetContent += `${masqRule}\n`;
743
- this.rules.push({
744
- tableFamily: family,
745
- tableName: this.tableName,
746
- chainName: postroutingChain,
747
- ruleContents: masqRule,
748
- added: false
749
- });
750
- }
751
- }
752
- // Apply the ruleset if we have any rules
753
- if (rulesetContent) {
754
- // Write to temporary file
755
- fs.writeFileSync(this.tempFilePath, rulesetContent);
756
- // Apply the ruleset
757
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} -f ${this.tempFilePath}`, this.settings.maxRetries, this.settings.retryDelayMs);
758
- this.log('info', `Added port forwarding rules for ${family}`);
759
- // Mark rules as added
760
- for (const rule of this.rules) {
761
- if (rule.tableFamily === family && !rule.added) {
762
- rule.added = true;
763
- // Verify the rule was applied
764
- await this.verifyRuleApplication(rule);
765
- }
766
- }
767
- // Remove temporary file
768
- fs.unlinkSync(this.tempFilePath);
769
- }
770
- return true;
771
- }
772
- catch (err) {
773
- this.log('error', `Failed to add port pair mappings: ${err.message}`);
774
- return false;
775
- }
776
- }
777
- /**
778
- * Setup quality of service rules
779
- */
780
- async addTrafficShaping(isIpv6 = false) {
781
- if (!this.settings.qos?.enabled) {
782
- return true;
783
- }
784
- const family = isIpv6 ? 'ip6' : 'ip';
785
- const qosChain = 'qos_forward';
786
- try {
787
- let rulesetContent = '';
788
- // Add rate limiting rule if specified
789
- if (this.settings.qos.maxRate) {
790
- const ruleContent = `add rule ${family} ${this.tableName} ${qosChain} ip daddr ${this.settings.toHost} ${this.settings.protocol} dport {${this.getAllPorts(this.settings.toPort)}} limit rate over ${this.settings.qos.maxRate} drop comment "${this.ruleTag}:QOS_RATE"`;
791
- rulesetContent += `${ruleContent}\n`;
792
- this.rules.push({
793
- tableFamily: family,
794
- tableName: this.tableName,
795
- chainName: qosChain,
796
- ruleContents: ruleContent,
797
- added: false
798
- });
799
- }
800
- // Add priority marking if specified
801
- if (this.settings.qos.priority !== undefined) {
802
- // Check if the chain exists
803
- const chainsOutput = await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} list chains ${family} ${this.tableName}`, this.settings.maxRetries, this.settings.retryDelayMs);
804
- // Check if we need to create priority queues
805
- const hasPrioChain = chainsOutput.includes(`chain prio${this.settings.qos.priority}`);
806
- if (!hasPrioChain) {
807
- // Create priority chain
808
- const prioChainRule = `add chain ${family} ${this.tableName} prio${this.settings.qos.priority} { type filter hook forward priority ${this.settings.qos.priority * 10}; }`;
809
- rulesetContent += `${prioChainRule}\n`;
810
- }
811
- // Add the rules to mark packets with this priority
812
- for (const range of this.normalizePortSpec(this.settings.toPort)) {
813
- const markRule = `add rule ${family} ${this.tableName} ${qosChain} ${this.settings.protocol} dport ${range.from}-${range.to} counter goto prio${this.settings.qos.priority} comment "${this.ruleTag}:QOS_PRIORITY"`;
814
- rulesetContent += `${markRule}\n`;
815
- this.rules.push({
816
- tableFamily: family,
817
- tableName: this.tableName,
818
- chainName: qosChain,
819
- ruleContents: markRule,
820
- added: false
821
- });
822
- }
823
- }
824
- // Apply the ruleset if we have any rules
825
- if (rulesetContent) {
826
- // Write to temporary file
827
- fs.writeFileSync(this.tempFilePath, rulesetContent);
828
- // Apply the ruleset
829
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} -f ${this.tempFilePath}`, this.settings.maxRetries, this.settings.retryDelayMs);
830
- this.log('info', `Added QoS rules for ${family}`);
831
- // Mark rules as added
832
- for (const rule of this.rules) {
833
- if (rule.tableFamily === family && !rule.added) {
834
- rule.added = true;
835
- // Verify the rule was applied
836
- await this.verifyRuleApplication(rule);
837
- }
838
- }
839
- // Remove temporary file
840
- fs.unlinkSync(this.tempFilePath);
841
- }
842
- return true;
843
- }
844
- catch (err) {
845
- this.log('error', `Failed to add traffic shaping: ${err.message}`);
846
- return false;
847
- }
848
- }
849
- /**
850
- * Setup NetworkProxy integration rules
851
- */
852
- async setupNetworkProxyIntegration(isIpv6 = false) {
853
- if (!this.settings.netProxyIntegration?.enabled) {
854
- return true;
855
- }
856
- const netProxyConfig = this.settings.netProxyIntegration;
857
- const family = isIpv6 ? 'ip6' : 'ip';
858
- const outputChain = 'nat_output';
859
- try {
860
- // Only proceed if we're redirecting localhost and have a port
861
- if (netProxyConfig.redirectLocalhost && netProxyConfig.sslTerminationPort) {
862
- const localhost = isIpv6 ? '::1' : '127.0.0.1';
863
- // Create the redirect rule
864
- const rule = `add rule ${family} ${this.tableName} ${outputChain} ${this.settings.protocol} daddr ${localhost} redirect to :${netProxyConfig.sslTerminationPort} comment "${this.ruleTag}:NETPROXY_REDIRECT"`;
865
- // Apply the rule
866
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} ${rule}`, this.settings.maxRetries, this.settings.retryDelayMs);
867
- this.log('info', `Added NetworkProxy redirection rule for ${family}`);
868
- const newRule = {
869
- tableFamily: family,
870
- tableName: this.tableName,
871
- chainName: outputChain,
872
- ruleContents: rule,
873
- added: true
874
- };
875
- this.rules.push(newRule);
876
- // Verify the rule was actually applied
877
- await this.verifyRuleApplication(newRule);
878
- }
879
- return true;
880
- }
881
- catch (err) {
882
- this.log('error', `Failed to set up NetworkProxy integration: ${err.message}`);
883
- return false;
884
- }
885
- }
886
- /**
887
- * Verify that a rule was successfully applied
888
- */
889
- async verifyRuleApplication(rule) {
890
- try {
891
- const { tableFamily, tableName, chainName, ruleContents } = rule;
892
- // Extract the distinctive parts of the rule to create a search pattern
893
- const commentMatch = ruleContents.match(/comment "([^"]+)"/);
894
- if (!commentMatch)
895
- return false;
896
- const commentTag = commentMatch[1];
897
- // List the chain to check if our rule is there
898
- const stdout = await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} list chain ${tableFamily} ${tableName} ${chainName}`, this.settings.maxRetries, this.settings.retryDelayMs);
899
- // Check if the comment appears in the output
900
- const isApplied = stdout.includes(commentTag);
901
- rule.verified = isApplied;
902
- if (!isApplied) {
903
- this.log('warn', `Rule verification failed: ${commentTag} not found in chain ${chainName}`);
904
- }
905
- else {
906
- this.log('debug', `Rule verified: ${commentTag} found in chain ${chainName}`);
907
- }
908
- return isApplied;
909
- }
910
- catch (err) {
911
- this.log('error', `Failed to verify rule application: ${err.message}`);
912
- return false;
913
- }
914
- }
915
- /**
916
- * Rolls back rules in case of error during setup
917
- */
918
- async rollbackRules() {
919
- // Process rules in reverse order (LIFO)
920
- for (let i = this.rules.length - 1; i >= 0; i--) {
921
- const rule = this.rules[i];
922
- if (rule.added) {
923
- try {
924
- // For nftables, create a delete rule by replacing 'add' with 'delete'
925
- const deleteRule = rule.ruleContents.replace('add rule', 'delete rule');
926
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} ${deleteRule}`, this.settings.maxRetries, this.settings.retryDelayMs);
927
- this.log('info', `Rolled back rule: ${deleteRule}`);
928
- rule.added = false;
929
- rule.verified = false;
930
- }
931
- catch (err) {
932
- this.log('error', `Failed to roll back rule: ${err.message}`);
933
- }
934
- }
935
- }
936
- }
937
- /**
938
- * Checks if nftables table exists
939
- */
940
- async tableExists(family, tableName) {
941
- try {
942
- const stdout = await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} list tables ${family}`, this.settings.maxRetries, this.settings.retryDelayMs);
943
- return stdout.includes(`table ${family} ${tableName}`);
944
- }
945
- catch (err) {
946
- return false;
947
- }
948
- }
949
- /**
950
- * Get system metrics like connection counts
951
- */
952
- async getSystemMetrics() {
953
- const metrics = {};
954
- try {
955
- // Try to get connection metrics if conntrack is available
956
- try {
957
- const stdout = await this.executeWithRetry('conntrack -C', this.settings.maxRetries, this.settings.retryDelayMs);
958
- metrics.activeConnections = parseInt(stdout.trim(), 10);
959
- }
960
- catch (err) {
961
- // conntrack not available, skip this metric
962
- }
963
- // Try to get forwarded connections count from nftables counters
964
- try {
965
- // Look for counters in our rules
966
- const stdout = await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} list table ip ${this.tableName}`, this.settings.maxRetries, this.settings.retryDelayMs);
967
- // Parse counter information from the output
968
- const counterMatches = stdout.matchAll(/counter packets (\d+) bytes (\d+)/g);
969
- let totalPackets = 0;
970
- let totalBytes = 0;
971
- for (const match of counterMatches) {
972
- totalPackets += parseInt(match[1], 10);
973
- totalBytes += parseInt(match[2], 10);
974
- }
975
- if (totalPackets > 0) {
976
- metrics.forwardedConnections = totalPackets;
977
- metrics.bytesForwarded = {
978
- sent: totalBytes,
979
- received: 0 // We can't easily determine this without additional rules
980
- };
981
- }
982
- }
983
- catch (err) {
984
- // Failed to get counter info, skip this metric
985
- }
986
- return metrics;
987
- }
988
- catch (err) {
989
- this.log('error', `Failed to get system metrics: ${err.message}`);
990
- return metrics;
991
- }
992
- }
993
- /**
994
- * Get status of IP sets
995
- */
996
- async getIPSetStatus() {
997
- const result = [];
998
- try {
999
- for (const family of ['ip', 'ip6']) {
1000
- try {
1001
- const stdout = await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} list sets ${family} ${this.tableName}`, this.settings.maxRetries, this.settings.retryDelayMs);
1002
- const setMatches = stdout.matchAll(/set (\w+) {\s*type (\w+)/g);
1003
- for (const match of setMatches) {
1004
- const setName = match[1];
1005
- const setType = match[2];
1006
- // Get element count from tracking map
1007
- const setKey = `${family}:${setName}`;
1008
- const elements = this.ipSets.get(setKey) || [];
1009
- result.push({
1010
- name: setName,
1011
- elementCount: elements.length,
1012
- type: setType
1013
- });
1014
- }
1015
- }
1016
- catch (err) {
1017
- // No sets for this family, or table doesn't exist
1018
- }
1019
- }
1020
- return result;
1021
- }
1022
- catch (err) {
1023
- this.log('error', `Failed to get IP set status: ${err.message}`);
1024
- return result;
1025
- }
1026
- }
1027
- /**
1028
- * Get detailed status about the current state of the proxy
1029
- */
1030
- async getStatus() {
1031
- const result = {
1032
- active: this.rules.some(r => r.added),
1033
- ruleCount: {
1034
- total: this.rules.length,
1035
- added: this.rules.filter(r => r.added).length,
1036
- verified: this.rules.filter(r => r.verified).length
1037
- },
1038
- tablesConfigured: [],
1039
- metrics: {},
1040
- qosEnabled: this.settings.qos?.enabled || false
1041
- };
1042
- try {
1043
- // Get list of configured tables
1044
- const stdout = await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} list tables`, this.settings.maxRetries, this.settings.retryDelayMs);
1045
- const tableRegex = /table (ip|ip6) (\w+)/g;
1046
- let match;
1047
- while ((match = tableRegex.exec(stdout)) !== null) {
1048
- const [, family, name] = match;
1049
- if (name === this.tableName) {
1050
- result.tablesConfigured.push({ family, tableName: name });
1051
- }
1052
- }
1053
- // Get system metrics
1054
- result.metrics = await this.getSystemMetrics();
1055
- // Get IP set status if using IP sets
1056
- if (this.settings.useIPSets) {
1057
- result.ipSetsConfigured = await this.getIPSetStatus();
1058
- }
1059
- return result;
1060
- }
1061
- catch (err) {
1062
- this.log('error', `Failed to get status: ${err.message}`);
1063
- return result;
1064
- }
1065
- }
1066
- /**
1067
- * Performs a dry run to see what commands would be executed without actually applying them
1068
- */
1069
- async dryRun() {
1070
- const commands = [];
1071
- // Simulate all the necessary setup steps and collect commands
1072
- // Tables and chains
1073
- commands.push(`add table ip ${this.tableName}`);
1074
- commands.push(`add chain ip ${this.tableName} nat_prerouting { type nat hook prerouting priority -100; }`);
1075
- if (!this.settings.preserveSourceIP) {
1076
- commands.push(`add chain ip ${this.tableName} nat_postrouting { type nat hook postrouting priority 100; }`);
1077
- }
1078
- if (this.settings.netProxyIntegration?.enabled && this.settings.netProxyIntegration.redirectLocalhost) {
1079
- commands.push(`add chain ip ${this.tableName} nat_output { type nat hook output priority 0; }`);
1080
- }
1081
- if (this.settings.qos?.enabled) {
1082
- commands.push(`add chain ip ${this.tableName} qos_forward { type filter hook forward priority 0; }`);
1083
- }
1084
- // Add IPv6 tables if enabled
1085
- if (this.settings.ipv6Support) {
1086
- commands.push(`add table ip6 ${this.tableName}`);
1087
- commands.push(`add chain ip6 ${this.tableName} nat_prerouting { type nat hook prerouting priority -100; }`);
1088
- if (!this.settings.preserveSourceIP) {
1089
- commands.push(`add chain ip6 ${this.tableName} nat_postrouting { type nat hook postrouting priority 100; }`);
1090
- }
1091
- if (this.settings.netProxyIntegration?.enabled && this.settings.netProxyIntegration.redirectLocalhost) {
1092
- commands.push(`add chain ip6 ${this.tableName} nat_output { type nat hook output priority 0; }`);
1093
- }
1094
- if (this.settings.qos?.enabled) {
1095
- commands.push(`add chain ip6 ${this.tableName} qos_forward { type filter hook forward priority 0; }`);
1096
- }
1097
- }
1098
- // Source IP filters
1099
- if (this.settings.useIPSets) {
1100
- if (this.settings.bannedSourceIPs?.length) {
1101
- commands.push(`add set ip ${this.tableName} banned_ips { type ipv4_addr; }`);
1102
- commands.push(`add element ip ${this.tableName} banned_ips { ${this.settings.bannedSourceIPs.join(', ')} }`);
1103
- commands.push(`add rule ip ${this.tableName} nat_prerouting ip saddr @banned_ips drop comment "${this.ruleTag}:BANNED_SET"`);
1104
- }
1105
- if (this.settings.allowedSourceIPs?.length) {
1106
- commands.push(`add set ip ${this.tableName} allowed_ips { type ipv4_addr; }`);
1107
- commands.push(`add element ip ${this.tableName} allowed_ips { ${this.settings.allowedSourceIPs.join(', ')} }`);
1108
- commands.push(`add rule ip ${this.tableName} nat_prerouting ip saddr @allowed_ips ${this.settings.protocol} dport {${this.getAllPorts(this.settings.fromPort)}} accept comment "${this.ruleTag}:ALLOWED_SET"`);
1109
- commands.push(`add rule ip ${this.tableName} nat_prerouting ${this.settings.protocol} dport {${this.getAllPorts(this.settings.fromPort)}} drop comment "${this.ruleTag}:DENY_ALL"`);
1110
- }
1111
- }
1112
- else if (this.settings.bannedSourceIPs?.length || this.settings.allowedSourceIPs?.length) {
1113
- // Traditional approach without IP sets
1114
- if (this.settings.bannedSourceIPs?.length) {
1115
- for (const ip of this.settings.bannedSourceIPs) {
1116
- commands.push(`add rule ip ${this.tableName} nat_prerouting ip saddr ${ip} drop comment "${this.ruleTag}:BANNED"`);
1117
- }
1118
- }
1119
- if (this.settings.allowedSourceIPs?.length) {
1120
- for (const ip of this.settings.allowedSourceIPs) {
1121
- commands.push(`add rule ip ${this.tableName} nat_prerouting ip saddr ${ip} ${this.settings.protocol} dport {${this.getAllPorts(this.settings.fromPort)}} accept comment "${this.ruleTag}:ALLOWED"`);
1122
- }
1123
- commands.push(`add rule ip ${this.tableName} nat_prerouting ${this.settings.protocol} dport {${this.getAllPorts(this.settings.fromPort)}} drop comment "${this.ruleTag}:DENY_ALL"`);
1124
- }
1125
- }
1126
- // Port forwarding rules
1127
- if (this.settings.useAdvancedNAT) {
1128
- // Advanced NAT with connection tracking
1129
- const fromPortRanges = this.normalizePortSpec(this.settings.fromPort);
1130
- const toPortRanges = this.normalizePortSpec(this.settings.toPort);
1131
- if (fromPortRanges.length === 1 && toPortRanges.length === 1) {
1132
- const fromRange = fromPortRanges[0];
1133
- const toRange = toPortRanges[0];
1134
- if (fromRange.from === fromRange.to && toRange.from === toRange.to) {
1135
- commands.push(`add rule ip ${this.tableName} nat_prerouting ${this.settings.protocol} dport ${fromRange.from} ct state new dnat to ${this.settings.toHost}:${toRange.from} comment "${this.ruleTag}:DNAT_CT"`);
1136
- }
1137
- else if ((fromRange.to - fromRange.from) === (toRange.to - toRange.from)) {
1138
- commands.push(`add rule ip ${this.tableName} nat_prerouting ${this.settings.protocol} dport ${fromRange.from}-${fromRange.to} ct state new dnat to ${this.settings.toHost}:${toRange.from}-${toRange.to} comment "${this.ruleTag}:DNAT_RANGE_CT"`);
1139
- }
1140
- commands.push(`add rule ip ${this.tableName} nat_prerouting ct state established,related accept comment "${this.ruleTag}:CT_ESTABLISHED"`);
1141
- }
1142
- }
1143
- else {
1144
- // Standard NAT rules
1145
- const fromRanges = this.normalizePortSpec(this.settings.fromPort);
1146
- const toRanges = this.normalizePortSpec(this.settings.toPort);
1147
- if (fromRanges.length === 1 && toRanges.length === 1) {
1148
- const fromRange = fromRanges[0];
1149
- const toRange = toRanges[0];
1150
- if (fromRange.from === fromRange.to && toRange.from === toRange.to) {
1151
- commands.push(`add rule ip ${this.tableName} nat_prerouting ${this.settings.protocol} dport ${fromRange.from} dnat to ${this.settings.toHost}:${toRange.from} comment "${this.ruleTag}:DNAT"`);
1152
- }
1153
- else {
1154
- commands.push(`add rule ip ${this.tableName} nat_prerouting ${this.settings.protocol} dport ${fromRange.from}-${fromRange.to} dnat to ${this.settings.toHost}:${toRange.from}-${toRange.to} comment "${this.ruleTag}:DNAT_RANGE"`);
1155
- }
1156
- }
1157
- else if (toRanges.length === 1) {
1158
- // One-to-many mapping
1159
- for (const fromRange of fromRanges) {
1160
- commands.push(`add rule ip ${this.tableName} nat_prerouting ${this.settings.protocol} dport ${fromRange.from}-${fromRange.to} dnat to ${this.settings.toHost}:${toRanges[0].from}-${toRanges[0].to} comment "${this.ruleTag}:DNAT_RANGE"`);
1161
- }
1162
- }
1163
- else {
1164
- // One-to-one mapping of multiple ranges
1165
- for (let i = 0; i < fromRanges.length; i++) {
1166
- commands.push(`add rule ip ${this.tableName} nat_prerouting ${this.settings.protocol} dport ${fromRanges[i].from}-${fromRanges[i].to} dnat to ${this.settings.toHost}:${toRanges[i].from}-${toRanges[i].to} comment "${this.ruleTag}:DNAT_RANGE"`);
1167
- }
1168
- }
1169
- }
1170
- // Masquerade rules if not preserving source IP
1171
- if (!this.settings.preserveSourceIP) {
1172
- commands.push(`add rule ip ${this.tableName} nat_postrouting ${this.settings.protocol} daddr ${this.settings.toHost} dport {${this.getAllPorts(this.settings.toPort)}} masquerade comment "${this.ruleTag}:MASQ"`);
1173
- }
1174
- // NetworkProxy integration
1175
- if (this.settings.netProxyIntegration?.enabled &&
1176
- this.settings.netProxyIntegration.redirectLocalhost &&
1177
- this.settings.netProxyIntegration.sslTerminationPort) {
1178
- commands.push(`add rule ip ${this.tableName} nat_output ${this.settings.protocol} daddr 127.0.0.1 redirect to :${this.settings.netProxyIntegration.sslTerminationPort} comment "${this.ruleTag}:NETPROXY_REDIRECT"`);
1179
- }
1180
- // QoS rules
1181
- if (this.settings.qos?.enabled) {
1182
- if (this.settings.qos.maxRate) {
1183
- commands.push(`add rule ip ${this.tableName} qos_forward ip daddr ${this.settings.toHost} ${this.settings.protocol} dport {${this.getAllPorts(this.settings.toPort)}} limit rate over ${this.settings.qos.maxRate} drop comment "${this.ruleTag}:QOS_RATE"`);
1184
- }
1185
- if (this.settings.qos.priority !== undefined) {
1186
- commands.push(`add chain ip ${this.tableName} prio${this.settings.qos.priority} { type filter hook forward priority ${this.settings.qos.priority * 10}; }`);
1187
- for (const range of this.normalizePortSpec(this.settings.toPort)) {
1188
- commands.push(`add rule ip ${this.tableName} qos_forward ${this.settings.protocol} dport ${range.from}-${range.to} counter goto prio${this.settings.qos.priority} comment "${this.ruleTag}:QOS_PRIORITY"`);
1189
- }
1190
- }
1191
- }
1192
- return commands;
1193
- }
1194
- /**
1195
- * Starts the proxy by setting up all nftables rules
1196
- */
1197
- async start() {
1198
- // Check if nftables is available
1199
- const nftablesAvailable = await this.checkNftablesAvailability();
1200
- if (!nftablesAvailable) {
1201
- throw new NftResourceError('nftables is not available or not properly configured');
1202
- }
1203
- // Optionally clean slate first
1204
- if (this.settings.forceCleanSlate) {
1205
- await NfTablesProxy.cleanSlate();
1206
- }
1207
- // Set up tables and chains for IPv4
1208
- const setupSuccess = await this.setupTablesAndChains();
1209
- if (!setupSuccess) {
1210
- throw new NftExecutionError('Failed to set up nftables tables and chains');
1211
- }
1212
- // Set up IPv6 tables and chains if enabled
1213
- if (this.settings.ipv6Support) {
1214
- const setupIPv6Success = await this.setupTablesAndChains(true);
1215
- if (!setupIPv6Success) {
1216
- this.log('warn', 'Failed to set up IPv6 tables and chains, continuing with IPv4 only');
1217
- }
1218
- }
1219
- // Add source IP filters
1220
- await this.addSourceIPFilters();
1221
- if (this.settings.ipv6Support) {
1222
- await this.addSourceIPFilters(true);
1223
- }
1224
- // Set up advanced NAT with connection tracking if enabled
1225
- if (this.settings.useAdvancedNAT) {
1226
- const advancedNatSuccess = await this.setupAdvancedNAT();
1227
- if (!advancedNatSuccess) {
1228
- this.log('warn', 'Failed to set up advanced NAT, falling back to standard NAT');
1229
- this.settings.useAdvancedNAT = false;
1230
- }
1231
- else if (this.settings.ipv6Support) {
1232
- await this.setupAdvancedNAT(true);
1233
- }
1234
- }
1235
- // Add port forwarding rules (skip if using advanced NAT)
1236
- if (!this.settings.useAdvancedNAT) {
1237
- const forwardingSuccess = await this.addPortForwardingRules();
1238
- if (!forwardingSuccess) {
1239
- throw new NftExecutionError('Failed to add port forwarding rules');
1240
- }
1241
- // Add IPv6 port forwarding rules if enabled
1242
- if (this.settings.ipv6Support) {
1243
- const forwardingIPv6Success = await this.addPortForwardingRules(true);
1244
- if (!forwardingIPv6Success) {
1245
- this.log('warn', 'Failed to add IPv6 port forwarding rules');
1246
- }
1247
- }
1248
- }
1249
- // Set up QoS if enabled
1250
- if (this.settings.qos?.enabled) {
1251
- const qosSuccess = await this.addTrafficShaping();
1252
- if (!qosSuccess) {
1253
- this.log('warn', 'Failed to set up QoS rules, continuing without traffic shaping');
1254
- }
1255
- else if (this.settings.ipv6Support) {
1256
- await this.addTrafficShaping(true);
1257
- }
1258
- }
1259
- // Set up NetworkProxy integration if enabled
1260
- if (this.settings.netProxyIntegration?.enabled) {
1261
- const netProxySetupSuccess = await this.setupNetworkProxyIntegration();
1262
- if (!netProxySetupSuccess) {
1263
- this.log('warn', 'Failed to set up NetworkProxy integration');
1264
- }
1265
- if (this.settings.ipv6Support) {
1266
- await this.setupNetworkProxyIntegration(true);
1267
- }
1268
- }
1269
- // Final check - ensure we have at least one rule added
1270
- if (this.rules.filter(r => r.added).length === 0) {
1271
- throw new NftExecutionError('No rules were added');
1272
- }
1273
- this.log('info', 'NfTablesProxy started successfully');
1274
- }
1275
- /**
1276
- * Stops the proxy by removing all added rules
1277
- */
1278
- async stop() {
1279
- try {
1280
- let rulesetContent = '';
1281
- // Process rules in reverse order (LIFO)
1282
- for (let i = this.rules.length - 1; i >= 0; i--) {
1283
- const rule = this.rules[i];
1284
- if (rule.added) {
1285
- // Create delete rules by replacing 'add' with 'delete'
1286
- const deleteRule = rule.ruleContents.replace('add rule', 'delete rule');
1287
- rulesetContent += `${deleteRule}\n`;
1288
- }
1289
- }
1290
- // Apply the ruleset if we have any rules to delete
1291
- if (rulesetContent) {
1292
- // Write to temporary file
1293
- fs.writeFileSync(this.tempFilePath, rulesetContent);
1294
- // Apply the ruleset
1295
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} -f ${this.tempFilePath}`, this.settings.maxRetries, this.settings.retryDelayMs);
1296
- this.log('info', 'Removed all added rules');
1297
- // Mark all rules as removed
1298
- this.rules.forEach(rule => {
1299
- rule.added = false;
1300
- rule.verified = false;
1301
- });
1302
- // Remove temporary file
1303
- fs.unlinkSync(this.tempFilePath);
1304
- }
1305
- // Clean up IP sets if we created any
1306
- if (this.settings.useIPSets && this.ipSets.size > 0) {
1307
- for (const [key, _] of this.ipSets) {
1308
- const [family, setName] = key.split(':');
1309
- try {
1310
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} delete set ${family} ${this.tableName} ${setName}`, this.settings.maxRetries, this.settings.retryDelayMs);
1311
- this.log('info', `Removed IP set ${setName} from ${family} ${this.tableName}`);
1312
- }
1313
- catch (err) {
1314
- this.log('warn', `Failed to remove IP set ${setName}: ${err.message}`);
1315
- }
1316
- }
1317
- this.ipSets.clear();
1318
- }
1319
- // Optionally clean up tables if they're empty
1320
- await this.cleanupEmptyTables();
1321
- this.log('info', 'NfTablesProxy stopped successfully');
1322
- }
1323
- catch (err) {
1324
- this.log('error', `Error stopping NfTablesProxy: ${err.message}`);
1325
- throw err;
1326
- }
1327
- }
1328
- /**
1329
- * Synchronous version of stop, for use in exit handlers
1330
- */
1331
- stopSync() {
1332
- try {
1333
- let rulesetContent = '';
1334
- // Process rules in reverse order (LIFO)
1335
- for (let i = this.rules.length - 1; i >= 0; i--) {
1336
- const rule = this.rules[i];
1337
- if (rule.added) {
1338
- // Create delete rules by replacing 'add' with 'delete'
1339
- const deleteRule = rule.ruleContents.replace('add rule', 'delete rule');
1340
- rulesetContent += `${deleteRule}\n`;
1341
- }
1342
- }
1343
- // Apply the ruleset if we have any rules to delete
1344
- if (rulesetContent) {
1345
- // Write to temporary file
1346
- fs.writeFileSync(this.tempFilePath, rulesetContent);
1347
- // Apply the ruleset
1348
- this.executeWithRetrySync(`${NfTablesProxy.NFT_CMD} -f ${this.tempFilePath}`, this.settings.maxRetries, this.settings.retryDelayMs);
1349
- this.log('info', 'Removed all added rules');
1350
- // Mark all rules as removed
1351
- this.rules.forEach(rule => {
1352
- rule.added = false;
1353
- rule.verified = false;
1354
- });
1355
- // Remove temporary file
1356
- fs.unlinkSync(this.tempFilePath);
1357
- }
1358
- // Clean up IP sets if we created any
1359
- if (this.settings.useIPSets && this.ipSets.size > 0) {
1360
- for (const [key, _] of this.ipSets) {
1361
- const [family, setName] = key.split(':');
1362
- try {
1363
- this.executeWithRetrySync(`${NfTablesProxy.NFT_CMD} delete set ${family} ${this.tableName} ${setName}`, this.settings.maxRetries, this.settings.retryDelayMs);
1364
- }
1365
- catch (err) {
1366
- // Non-critical error, continue
1367
- }
1368
- }
1369
- }
1370
- // Optionally clean up tables if they're empty (sync version)
1371
- this.cleanupEmptyTablesSync();
1372
- this.log('info', 'NfTablesProxy stopped successfully');
1373
- }
1374
- catch (err) {
1375
- this.log('error', `Error stopping NfTablesProxy: ${err.message}`);
1376
- }
1377
- }
1378
- /**
1379
- * Cleans up empty tables
1380
- */
1381
- async cleanupEmptyTables() {
1382
- // Check if tables are empty, and if so, delete them
1383
- for (const family of ['ip', 'ip6']) {
1384
- // Skip IPv6 if not enabled
1385
- if (family === 'ip6' && !this.settings.ipv6Support) {
1386
- continue;
1387
- }
1388
- try {
1389
- // Check if table exists
1390
- const tableExists = await this.tableExists(family, this.tableName);
1391
- if (!tableExists) {
1392
- continue;
1393
- }
1394
- // Check if the table has any rules
1395
- const stdout = await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} list table ${family} ${this.tableName}`, this.settings.maxRetries, this.settings.retryDelayMs);
1396
- const hasRules = stdout.includes('rule');
1397
- if (!hasRules) {
1398
- // Table is empty, delete it
1399
- await this.executeWithRetry(`${NfTablesProxy.NFT_CMD} delete table ${family} ${this.tableName}`, this.settings.maxRetries, this.settings.retryDelayMs);
1400
- this.log('info', `Deleted empty table ${family} ${this.tableName}`);
1401
- }
1402
- }
1403
- catch (err) {
1404
- this.log('error', `Error cleaning up tables: ${err.message}`);
1405
- }
1406
- }
1407
- }
1408
- /**
1409
- * Synchronous version of cleanupEmptyTables
1410
- */
1411
- cleanupEmptyTablesSync() {
1412
- // Check if tables are empty, and if so, delete them
1413
- for (const family of ['ip', 'ip6']) {
1414
- // Skip IPv6 if not enabled
1415
- if (family === 'ip6' && !this.settings.ipv6Support) {
1416
- continue;
1417
- }
1418
- try {
1419
- // Check if table exists
1420
- const tableExistsOutput = this.executeWithRetrySync(`${NfTablesProxy.NFT_CMD} list tables ${family}`, this.settings.maxRetries, this.settings.retryDelayMs);
1421
- const tableExists = tableExistsOutput.includes(`table ${family} ${this.tableName}`);
1422
- if (!tableExists) {
1423
- continue;
1424
- }
1425
- // Check if the table has any rules
1426
- const stdout = this.executeWithRetrySync(`${NfTablesProxy.NFT_CMD} list table ${family} ${this.tableName}`, this.settings.maxRetries, this.settings.retryDelayMs);
1427
- const hasRules = stdout.includes('rule');
1428
- if (!hasRules) {
1429
- // Table is empty, delete it
1430
- this.executeWithRetrySync(`${NfTablesProxy.NFT_CMD} delete table ${family} ${this.tableName}`, this.settings.maxRetries, this.settings.retryDelayMs);
1431
- this.log('info', `Deleted empty table ${family} ${this.tableName}`);
1432
- }
1433
- }
1434
- catch (err) {
1435
- this.log('error', `Error cleaning up tables: ${err.message}`);
1436
- }
1437
- }
1438
- }
1439
- /**
1440
- * Removes all nftables rules created by this module
1441
- */
1442
- static async cleanSlate() {
1443
- try {
1444
- // Check for rules with our comment pattern
1445
- const stdout = await execAsync(`${NfTablesProxy.NFT_CMD} list ruleset`);
1446
- // Extract our tables
1447
- const tableMatches = stdout.stdout.match(/table (ip|ip6) (\w+) {[^}]*NfTablesProxy:[^}]*}/g);
1448
- if (tableMatches) {
1449
- for (const tableMatch of tableMatches) {
1450
- // Extract table family and name
1451
- const familyMatch = tableMatch.match(/table (ip|ip6) (\w+)/);
1452
- if (familyMatch) {
1453
- const family = familyMatch[1];
1454
- const tableName = familyMatch[2];
1455
- // Delete the table
1456
- await execAsync(`${NfTablesProxy.NFT_CMD} delete table ${family} ${tableName}`);
1457
- console.log(`Deleted table ${family} ${tableName} containing NfTablesProxy rules`);
1458
- }
1459
- }
1460
- }
1461
- else {
1462
- console.log('No NfTablesProxy rules found to clean up');
1463
- }
1464
- }
1465
- catch (err) {
1466
- console.error(`Error in cleanSlate: ${err}`);
1467
- }
1468
- }
1469
- /**
1470
- * Synchronous version of cleanSlate
1471
- */
1472
- static cleanSlateSync() {
1473
- try {
1474
- // Check for rules with our comment pattern
1475
- const stdout = execSync(`${NfTablesProxy.NFT_CMD} list ruleset`).toString();
1476
- // Extract our tables
1477
- const tableMatches = stdout.match(/table (ip|ip6) (\w+) {[^}]*NfTablesProxy:[^}]*}/g);
1478
- if (tableMatches) {
1479
- for (const tableMatch of tableMatches) {
1480
- // Extract table family and name
1481
- const familyMatch = tableMatch.match(/table (ip|ip6) (\w+)/);
1482
- if (familyMatch) {
1483
- const family = familyMatch[1];
1484
- const tableName = familyMatch[2];
1485
- // Delete the table
1486
- execSync(`${NfTablesProxy.NFT_CMD} delete table ${family} ${tableName}`);
1487
- console.log(`Deleted table ${family} ${tableName} containing NfTablesProxy rules`);
1488
- }
1489
- }
1490
- }
1491
- else {
1492
- console.log('No NfTablesProxy rules found to clean up');
1493
- }
1494
- }
1495
- catch (err) {
1496
- console.error(`Error in cleanSlateSync: ${err}`);
1497
- }
1498
- }
1499
- /**
1500
- * Improved logging with structured output
1501
- */
1502
- log(level, message, meta) {
1503
- if (!this.settings.enableLogging && (level === 'info' || level === 'debug')) {
1504
- return;
1505
- }
1506
- const timestamp = new Date().toISOString();
1507
- const logData = {
1508
- timestamp,
1509
- level: level.toUpperCase(),
1510
- message,
1511
- ...meta,
1512
- context: {
1513
- instance: this.ruleTag,
1514
- table: this.tableName
1515
- }
1516
- };
1517
- // Determine if output should be JSON or plain text based on settings
1518
- const useJson = this.settings.logFormat === 'json';
1519
- if (useJson) {
1520
- const logOutput = JSON.stringify(logData);
1521
- console.log(logOutput);
1522
- return;
1523
- }
1524
- // Plain text format
1525
- const metaStr = meta ? ` ${JSON.stringify(meta)}` : '';
1526
- switch (level) {
1527
- case 'info':
1528
- console.log(`[${timestamp}] [INFO] ${message}${metaStr}`);
1529
- break;
1530
- case 'warn':
1531
- console.warn(`[${timestamp}] [WARN] ${message}${metaStr}`);
1532
- break;
1533
- case 'error':
1534
- console.error(`[${timestamp}] [ERROR] ${message}${metaStr}`);
1535
- break;
1536
- case 'debug':
1537
- console.log(`[${timestamp}] [DEBUG] ${message}${metaStr}`);
1538
- break;
1539
- }
1540
- }
1541
- }
1542
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5uZnRhYmxlc3Byb3h5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvbmZ0dGFibGVzcHJveHkvY2xhc3Nlcy5uZnRhYmxlc3Byb3h5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQy9DLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDakMsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFFekIsTUFBTSxTQUFTLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO0FBRWxDOztHQUVHO0FBQ0gsTUFBTSxPQUFPLFlBQWEsU0FBUSxLQUFLO0lBQ3JDLFlBQVksT0FBZTtRQUN6QixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLGNBQWMsQ0FBQztJQUM3QixDQUFDO0NBQ0Y7QUFFRCxNQUFNLE9BQU8sa0JBQW1CLFNBQVEsWUFBWTtJQUNsRCxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxvQkFBb0IsQ0FBQztJQUNuQyxDQUFDO0NBQ0Y7QUFFRCxNQUFNLE9BQU8saUJBQWtCLFNBQVEsWUFBWTtJQUNqRCxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxtQkFBbUIsQ0FBQztJQUNsQyxDQUFDO0NBQ0Y7QUFFRCxNQUFNLE9BQU8sZ0JBQWlCLFNBQVEsWUFBWTtJQUNoRCxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FB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