Compare commits

...

186 Commits

Author SHA1 Message Date
Shizun Ge 5d27ee12f8 Merge pull request #214 from shizunge/dependabot/github_actions/actions/checkout-7
Bump actions/checkout from 6 to 7
2026-06-22 12:37:19 -07:00
dependabot[bot] 637aa0fcc4 Bump actions/checkout from 6 to 7
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-22 08:15:08 +00:00
Shizun Ge bb02fb0180 Merge pull request #213 from adamanteye/main
[dashboard] Filter on cluster, namespace, and job
2026-06-11 12:23:47 -07:00
Shizun Ge 9100b14abf Merge pull request #209 from shizunge/dependabot/go_modules/github.com/pires/go-proxyproto-0.12.0
Bump github.com/pires/go-proxyproto from 0.11.0 to 0.12.0
2026-06-06 18:47:58 -07:00
Shizun Ge b7fdabf81e Merge branch 'main' into dependabot/go_modules/github.com/pires/go-proxyproto-0.12.0 2026-06-06 18:38:24 -07:00
Shizun Ge 9b9c174b84 Merge pull request #211 from shizunge/dependabot/github_actions/docker/login-action-4.2.0
Bump docker/login-action from 4.1.0 to 4.2.0
2026-06-06 18:35:41 -07:00
Shizun Ge bc43eca7de Merge pull request #210 from shizunge/dependabot/github_actions/docker/setup-buildx-action-4.1.0
Bump docker/setup-buildx-action from 4.0.0 to 4.1.0
2026-06-06 18:35:28 -07:00
Shizun Ge a059852463 Merge pull request #208 from shizunge/dependabot/go_modules/github.com/pierrre/geohash-1.1.4
Bump github.com/pierrre/geohash from 1.1.3 to 1.1.4
2026-06-06 18:35:00 -07:00
Shizun Ge 8b180ee911 Merge pull request #212 from shizunge/dependabot/github_actions/docker/build-push-action-7.2.0
Bump docker/build-push-action from 7.0.0 to 7.2.0
2026-06-06 18:34:44 -07:00
Xuelin Yang 2fd6c7a407 [dashboard] Filter on cluster, namespace, and job 2026-06-06 16:40:20 +08:00
dependabot[bot] eddce4b85a Bump docker/build-push-action from 7.0.0 to 7.2.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 7.0.0 to 7.2.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v7.0.0...v7.2.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 12:03:40 +00:00
dependabot[bot] 591ad1be81 Bump docker/login-action from 4.1.0 to 4.2.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 4.1.0 to 4.2.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v4.1.0...v4.2.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 12:03:34 +00:00
dependabot[bot] 2c421593a3 Bump docker/setup-buildx-action from 4.0.0 to 4.1.0
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v4.0.0...v4.1.0)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-25 12:03:31 +00:00
dependabot[bot] 15e848bcd7 Bump github.com/pires/go-proxyproto from 0.11.0 to 0.12.0
Bumps [github.com/pires/go-proxyproto](https://github.com/pires/go-proxyproto) from 0.11.0 to 0.12.0.
- [Release notes](https://github.com/pires/go-proxyproto/releases)
- [Commits](https://github.com/pires/go-proxyproto/compare/v0.11.0...v0.12.0)

---
updated-dependencies:
- dependency-name: github.com/pires/go-proxyproto
  dependency-version: 0.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-20 08:50:06 +00:00
dependabot[bot] d2fc221cb2 Bump github.com/pierrre/geohash from 1.1.3 to 1.1.4
Bumps [github.com/pierrre/geohash](https://github.com/pierrre/geohash) from 1.1.3 to 1.1.4.
- [Commits](https://github.com/pierrre/geohash/compare/v1.1.3...v1.1.4)

---
updated-dependencies:
- dependency-name: github.com/pierrre/geohash
  dependency-version: 1.1.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-13 08:31:55 +00:00
Shizun Ge 816b060a1c Merge pull request #205 from shizunge/dependabot/github_actions/docker/login-action-4.1.0
Bump docker/login-action from 4.0.0 to 4.1.0
2026-04-07 09:25:46 -07:00
dependabot[bot] 9db64900e0 Bump docker/login-action from 4.0.0 to 4.1.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v4.0.0...v4.1.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-06 08:20:18 +00:00
Shizun Ge 8631efdc1c Merge pull request #204 from shizunge/dependabot/go_modules/github.com/pires/go-proxyproto-0.11.0
Bump github.com/pires/go-proxyproto from 0.8.1 to 0.11.0
2026-03-30 10:37:49 -07:00
dependabot[bot] 4d9fe71b39 Bump github.com/pires/go-proxyproto from 0.8.1 to 0.11.0
Bumps [github.com/pires/go-proxyproto](https://github.com/pires/go-proxyproto) from 0.8.1 to 0.11.0.
- [Release notes](https://github.com/pires/go-proxyproto/releases)
- [Commits](https://github.com/pires/go-proxyproto/compare/v0.8.1...v0.11.0)

---
updated-dependencies:
- dependency-name: github.com/pires/go-proxyproto
  dependency-version: 0.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-30 08:24:34 +00:00
Shizun Ge f0045d32fc [dashboard] Change map circle fill opacity to 0.8 2026-03-28 22:27:46 -07:00
Shizun Ge 3da6dd03b3 [workflows] fix integration tests. 2026-03-26 21:58:14 -07:00
Shizun Ge cc3e0539ff update go to 1.26.1 2026-03-26 21:38:35 -07:00
Shizun Ge 5b3b5973c3 Merge pull request #203 from adamanteye/main
examples/kustomize-simple: add k8s manifests
2026-03-23 21:58:11 -07:00
Xuelin Yang 4bc342b136 examples/kustomize-simple: readonly root filesystem 2026-03-24 12:03:34 +08:00
Xuelin Yang 66244e80a7 examples: sort examples alphabetically 2026-03-24 10:34:19 +08:00
Xuelin Yang 16a32d06cd examples/kustomize-simple: add k8s manifests 2026-03-23 21:42:31 +08:00
Shizun Ge 1e5f0a29ea Merge pull request #202 from BenjaminGoehry/test/prometheus_test
test: add prometheus metrics integration test
2026-03-21 22:09:28 -07:00
Ben G 4344bfbde4 test: add prometheus metrics integration test 2026-03-20 20:42:59 +01:00
Shizun Ge f6e922f36f Merge pull request #196 from DarkWolfCave/fix/ghost-connections
Add TCP keepalive and write deadline on accepted connections
2026-03-17 15:47:54 -07:00
darkwolf cf6fbb5f41 use min(interval, 30s) for TCP keepalive period
Adapt keepalive to the configured interval: for short intervals
(e.g. 10s) detection is faster, for long intervals (e.g. 10min)
it caps at 30s as a safety net. Add comments explaining what
problem keepalive solves and its detection time limitation.
2026-03-17 06:40:43 +01:00
darkwolf ac07a37754 remove unnecessary panic recovery in send goroutine
There is no concrete panic path in the send flow — Write() and
SetWriteDeadline() return errors, not panics. The defer/recover
was overly defensive and could mask real bugs.
2026-03-12 10:56:53 +01:00
darkwolf b6b3fe2678 refactor: use interval as write deadline instead of separate parameter
Simplify the ghost connection fix by reusing the existing interval
duration as the write deadline. This removes the need for a separate
-write_deadline_ms flag while maintaining the same protection against
goroutine leaks from dead connections.
2026-03-12 09:26:38 +01:00
Shizun Ge 3832d95f14 Merge pull request #197 from shizunge/dependabot/github_actions/docker/build-push-action-7.0.0
Bump docker/build-push-action from 6.19.2 to 7.0.0
2026-03-11 21:40:18 -07:00
Shizun Ge 33129ba155 Merge pull request #198 from shizunge/dependabot/github_actions/docker/login-action-4.0.0
Bump docker/login-action from 3.7.0 to 4.0.0
2026-03-11 21:40:09 -07:00
Shizun Ge 7d5eed824d Merge pull request #199 from shizunge/dependabot/github_actions/docker/metadata-action-6
Bump docker/metadata-action from 5 to 6
2026-03-11 21:40:03 -07:00
Shizun Ge 43859e73f2 Merge pull request #200 from shizunge/dependabot/github_actions/docker/setup-qemu-action-4
Bump docker/setup-qemu-action from 3 to 4
2026-03-11 21:39:57 -07:00
Shizun Ge 005145242c Merge pull request #201 from shizunge/dependabot/github_actions/docker/setup-buildx-action-4.0.0
Bump docker/setup-buildx-action from 3.12.0 to 4.0.0
2026-03-11 21:39:49 -07:00
dependabot[bot] a677b35f05 Bump docker/setup-buildx-action from 3.12.0 to 4.0.0
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.12.0 to 4.0.0.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3.12.0...v4.0.0)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: 4.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 08:27:16 +00:00
dependabot[bot] 760b9cfb6b Bump docker/setup-qemu-action from 3 to 4
Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 3 to 4.
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 08:27:11 +00:00
dependabot[bot] 7bfa69cba0 Bump docker/metadata-action from 5 to 6
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 5 to 6.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Commits](https://github.com/docker/metadata-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 08:27:07 +00:00
dependabot[bot] 35b2cb887c Bump docker/login-action from 3.7.0 to 4.0.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.7.0 to 4.0.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3.7.0...v4.0.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 4.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 08:27:01 +00:00
dependabot[bot] b6200c5030 Bump docker/build-push-action from 6.19.2 to 7.0.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.19.2 to 7.0.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.19.2...v7.0.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 08:26:57 +00:00
Shizun Ge ca1d51b594 Merge pull request #194 from shizunge/dependabot/github_actions/actions/setup-go-6
Bump actions/setup-go from 5 to 6
2026-03-02 21:15:42 -08:00
Shizun Ge 9292291cbd Merge pull request #193 from shizunge/dependabot/github_actions/actions/checkout-6
Bump actions/checkout from 4 to 6
2026-03-02 21:15:25 -08:00
Shizun Ge 62a54396cd Merge pull request #192 from BenjaminGoehry/fix/integration_test
fix: integration test concurrency
2026-03-02 21:15:02 -08:00
Ben G ebbcd539fc fix: integration test concurrency
increase timeouts

clean

fix

fix

fix
2026-03-02 21:33:46 +01:00
darkwolf ecdfc514d0 Fix ghost connection goroutine leak via write deadline and TCP keepalive
Connections closed by the kernel but not detected by endlessh-go cause
goroutines to run indefinitely, drifting open/closed Prometheus counters.
This happens because conn.Write() succeeds on dead connections when the
kernel buffers data. Kernel 6.12 (Debian 13) is more aggressive at
buffering, making ghosts permanent rather than self-healing.

Changes:
- Add SetWriteDeadline before conn.Write to detect dead connections
- Enable TCP keepalive (30s) on accepted connections for kernel-level
  dead peer detection
- Add defer/recover in send goroutine for robustness
- Add -write_deadline_ms flag (default 30000, 0 to disable)

No new dependencies - uses only Go stdlib net package functions.
2026-03-02 19:14:07 +01:00
dependabot[bot] b088bdbd15 Bump actions/setup-go from 5 to 6
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5 to 6.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-02 08:28:14 +00:00
dependabot[bot] 5a88627724 Bump actions/checkout from 4 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-02 08:28:09 +00:00
Shizun Ge 3fd26b15db Merge pull request #188 from BenjaminGoehry/test/integration_test
test: add integration tests for multi-port, tarpit behavior, and max_clients limit
2026-02-23 21:28:21 -08:00
Ben G df8978a8f1 review 2026-02-24 00:03:26 +01:00
Shizun Ge 1133f6ad28 Merge pull request #191 from shizunge/dependabot/github_actions/docker/build-push-action-6.19.2
Bump docker/build-push-action from 6.18.0 to 6.19.2
2026-02-18 20:43:29 -08:00
dependabot[bot] 869e25828b Bump docker/build-push-action from 6.18.0 to 6.19.2
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.18.0 to 6.19.2.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.18.0...v6.19.2)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 6.19.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-16 08:25:03 +00:00
Ben G eea67a33b1 fix server for random port and review 2026-02-09 23:38:27 +01:00
Shizun Ge cfb21bf1c5 Merge pull request #189 from shizunge/dependabot/github_actions/docker/login-action-3.7.0
Bump docker/login-action from 3.6.0 to 3.7.0
2026-02-05 22:21:39 -08:00
dependabot[bot] 3d6365caf0 Bump docker/login-action from 3.6.0 to 3.7.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.6.0 to 3.7.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3.6.0...v3.7.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 3.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-02 08:39:53 +00:00
Ben G 5fa58afc0b fix 2026-01-29 22:16:32 +01:00
Ben G ac6cda3e73 update github workflow with test job 2026-01-29 22:14:45 +01:00
Ben G f48f6d748f test(integration): add multiple ports behavior, tarpit heavior check and concurrency respecting max_clients 2026-01-28 14:12:15 +01:00
Shizun Ge 0d5395b4ee Update copyright to 2026. 2026-01-05 20:07:30 -08:00
Shizun Ge 1585df7876 Merge pull request #187 from shizunge/dependabot/github_actions/docker/setup-buildx-action-3.12.0
Bump docker/setup-buildx-action from 3.11.1 to 3.12.0
2025-12-24 22:32:46 -08:00
dependabot[bot] 07df006502 Bump docker/setup-buildx-action from 3.11.1 to 3.12.0
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.11.1 to 3.12.0.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3.11.1...v3.12.0)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: 3.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-22 08:01:45 +00:00
Shizun Ge 829fe080a8 Merge pull request #186 from shizunge/dependabot/github_actions/actions/checkout-6
Bump actions/checkout from 5 to 6
2025-11-24 10:44:01 -08:00
dependabot[bot] 63b07abf45 Bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-24 08:02:13 +00:00
Shizun Ge b4077f7002 [dashboard] Add ports selection. 2025-11-07 00:34:28 -08:00
Shizun Ge f64550176c Merge pull request #184 from shizunge/dependabot/github_actions/docker/login-action-3.6.0
Bump docker/login-action from 3.5.0 to 3.6.0
2025-10-06 10:47:04 -07:00
Shizun Ge 3c60cdf2ed Merge pull request #185 from shizunge/dependabot/github_actions/peter-evans/dockerhub-description-5
Bump peter-evans/dockerhub-description from 4 to 5
2025-10-06 10:46:56 -07:00
dependabot[bot] 5e3b96cc65 Bump peter-evans/dockerhub-description from 4 to 5
Bumps [peter-evans/dockerhub-description](https://github.com/peter-evans/dockerhub-description) from 4 to 5.
- [Release notes](https://github.com/peter-evans/dockerhub-description/releases)
- [Commits](https://github.com/peter-evans/dockerhub-description/compare/v4...v5)

---
updated-dependencies:
- dependency-name: peter-evans/dockerhub-description
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 08:02:22 +00:00
dependabot[bot] f6e2189c79 Bump docker/login-action from 3.5.0 to 3.6.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.5.0 to 3.6.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3.5.0...v3.6.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 3.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 08:02:19 +00:00
Shizun Ge 5fadfc1cc3 Merge pull request #181 from firstred/proxy-protocol
Add PROXY protocol support
2025-09-11 17:33:32 -07:00
Michael Dekker e1a2425ced Add PROXY protocol support 2025-09-12 00:00:26 +02:00
Shizun Ge 2470ee67d7 Merge pull request #180 from dataprolet/main
Remove obsolete "version" from compose files
2025-09-09 08:16:04 -07:00
dataprolet 5cf0b1fa3f Remove obsolete version 2025-09-09 16:33:56 +02:00
dataprolet 61483cde46 Remove obsolete version 2025-09-09 16:33:37 +02:00
Shizun Ge 37a5392166 Merge pull request #179 from shizunge/dependabot/go_modules/github.com/prometheus/client_golang-1.23.2
Bump github.com/prometheus/client_golang from 1.23.0 to 1.23.2
2025-09-08 11:37:58 -07:00
dependabot[bot] 02c896ba89 Bump github.com/prometheus/client_golang from 1.23.0 to 1.23.2
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.23.0 to 1.23.2.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.23.0...v1.23.2)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.23.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 08:14:01 +00:00
Shizun Ge e6070444c8 Merge pull request #178 from shizunge/dependabot/github_actions/actions/checkout-5
Bump actions/checkout from 4 to 5
2025-08-25 09:58:11 -07:00
dependabot[bot] 0aa99ef83b Bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 15:04:03 +00:00
Shizun Ge 1518c37fe7 Merge pull request #177 from shizunge/dependabot/github_actions/docker/login-action-3.5.0
Bump docker/login-action from 3.4.0 to 3.5.0
2025-08-12 00:40:08 -07:00
dependabot[bot] 7b30a30a37 Bump docker/login-action from 3.4.0 to 3.5.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.4.0 to 3.5.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3.4.0...v3.5.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 3.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 12:13:20 +00:00
Shizun Ge c0db3758a8 Merge pull request #176 from shizunge/dependabot/go_modules/github.com/prometheus/client_golang-1.23.0
Bump github.com/prometheus/client_golang from 1.22.0 to 1.23.0
2025-08-04 08:54:34 -07:00
dependabot[bot] 0ef5dd1d16 Bump github.com/prometheus/client_golang from 1.22.0 to 1.23.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.22.0 to 1.23.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.22.0...v1.23.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 11:21:18 +00:00
Shizun Ge 644d2808f0 Add badges 2025-07-26 02:27:54 -07:00
Shizun Ge 35477d6c2b Merge pull request #175 from shizunge/dependabot/go_modules/github.com/oschwald/geoip2-golang-1.13.0
Bump github.com/oschwald/geoip2-golang from 1.11.0 to 1.13.0
2025-07-14 06:33:40 -07:00
dependabot[bot] 953a76b638 Bump github.com/oschwald/geoip2-golang from 1.11.0 to 1.13.0
Bumps [github.com/oschwald/geoip2-golang](https://github.com/oschwald/geoip2-golang) from 1.11.0 to 1.13.0.
- [Release notes](https://github.com/oschwald/geoip2-golang/releases)
- [Changelog](https://github.com/oschwald/geoip2-golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/oschwald/geoip2-golang/compare/v1.11.0...v1.13.0)

---
updated-dependencies:
- dependency-name: github.com/oschwald/geoip2-golang
  dependency-version: 1.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 10:37:24 +00:00
Shizun Ge 97dd54bbb4 Merge pull request #174 from vst-name/main
Fixed type in error logs in metrics.go
2025-07-07 10:36:52 -07:00
Vladislav Stishenko d5d671b74d Fixed type in error logs in metrics.go
Signed-off-by: Vladislav Stishenko <github@vst.name>
2025-06-29 20:19:15 +05:00
Shizun Ge dbec0d7b36 Merge pull request #171 from agneum14/country-panel-title-case
Make the country connections panel title case
2025-06-25 10:15:38 -07:00
Shizun Ge 2ae998243b Merge pull request #173 from shizunge/dependabot/github_actions/docker/setup-buildx-action-3.11.1
Bump docker/setup-buildx-action from 3.10.0 to 3.11.1
2025-06-25 10:13:00 -07:00
Shizun Ge 22e7d84792 Merge pull request #172 from shizunge/dependabot/go_modules/github.com/pierrre/geohash-1.1.3
Bump github.com/pierrre/geohash from 1.1.2 to 1.1.3
2025-06-25 10:12:49 -07:00
Shizun Ge 3691c01bcf Merge pull request #167 from shizunge/dependabot/go_modules/github.com/golang/glog-1.2.5
Bump github.com/golang/glog from 1.2.4 to 1.2.5
2025-06-25 10:12:33 -07:00
Shizun Ge cedc9b0598 Merge pull request #170 from shizunge/dependabot/github_actions/docker/build-push-action-6.18.0
Bump docker/build-push-action from 6.15.0 to 6.18.0
2025-06-25 10:12:16 -07:00
dependabot[bot] 4c98088fc6 Bump docker/setup-buildx-action from 3.10.0 to 3.11.1
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.10.0 to 3.11.1.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3.10.0...v3.11.1)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: 3.11.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-23 09:37:44 +00:00
dependabot[bot] 602e22b631 Bump github.com/pierrre/geohash from 1.1.2 to 1.1.3
Bumps [github.com/pierrre/geohash](https://github.com/pierrre/geohash) from 1.1.2 to 1.1.3.
- [Commits](https://github.com/pierrre/geohash/compare/v1.1.2...v1.1.3)

---
updated-dependencies:
- dependency-name: github.com/pierrre/geohash
  dependency-version: 1.1.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-16 09:10:27 +00:00
Andrew G. Neumann b81117a9de Make the country connections panel title case 2025-06-04 21:16:49 -04:00
dependabot[bot] 502efbfcc2 Bump docker/build-push-action from 6.15.0 to 6.18.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.15.0 to 6.18.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.15.0...v6.18.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 6.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 09:27:37 +00:00
dependabot[bot] 2e39a6194f Bump github.com/golang/glog from 1.2.4 to 1.2.5
Bumps [github.com/golang/glog](https://github.com/golang/glog) from 1.2.4 to 1.2.5.
- [Release notes](https://github.com/golang/glog/releases)
- [Commits](https://github.com/golang/glog/compare/v1.2.4...v1.2.5)

---
updated-dependencies:
- dependency-name: github.com/golang/glog
  dependency-version: 1.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-05 08:42:00 +00:00
Shizun Ge 93181ac5b3 [workflow] Ignore dependabot on push 2025-04-23 10:10:46 -07:00
Shizun Ge cfa86895ea Merge pull request #158 from shizunge/dependabot/github_actions/docker/setup-buildx-action-3.10.0
Bump docker/setup-buildx-action from 3.8.0 to 3.10.0
2025-04-17 23:13:59 -07:00
Shizun Ge c86d19a55f Merge pull request #159 from shizunge/dependabot/github_actions/docker/build-push-action-6.15.0
Bump docker/build-push-action from 6.11.0 to 6.15.0
2025-04-17 23:13:48 -07:00
Shizun Ge 4a02af0905 Merge pull request #161 from shizunge/dependabot/github_actions/docker/login-action-3.4.0
Bump docker/login-action from 3.3.0 to 3.4.0
2025-04-17 23:13:37 -07:00
Shizun Ge 9aa45d5151 Merge pull request #152 from shizunge/dependabot/go_modules/github.com/golang/glog-1.2.4
Bump github.com/golang/glog from 1.2.3 to 1.2.4
2025-04-17 23:09:04 -07:00
dependabot[bot] c2a3afedbc Bump github.com/golang/glog from 1.2.3 to 1.2.4
Bumps [github.com/golang/glog](https://github.com/golang/glog) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/golang/glog/releases)
- [Commits](https://github.com/golang/glog/compare/v1.2.3...v1.2.4)

---
updated-dependencies:
- dependency-name: github.com/golang/glog
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-18 06:07:35 +00:00
Shizun Ge 529a185781 Merge pull request #165 from shizunge/dependabot/go_modules/github.com/prometheus/client_golang-1.22.0
Bump github.com/prometheus/client_golang from 1.20.5 to 1.22.0
2025-04-17 23:06:20 -07:00
Shizun Ge 789c569d22 fix workflow names 2025-04-17 23:05:17 -07:00
dependabot[bot] 8c5f4b46d1 Bump docker/setup-buildx-action from 3.8.0 to 3.10.0
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.8.0 to 3.10.0.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3.8.0...v3.10.0)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-18 06:04:34 +00:00
dependabot[bot] 5c145553ff Bump docker/build-push-action from 6.11.0 to 6.15.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.11.0 to 6.15.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.11.0...v6.15.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-18 06:04:23 +00:00
dependabot[bot] b960bb9f52 Bump docker/login-action from 3.3.0 to 3.4.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3.3.0...v3.4.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-18 06:04:08 +00:00
dependabot[bot] f196e91efd Bump github.com/prometheus/client_golang from 1.20.5 to 1.22.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.5 to 1.22.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.20.5...v1.22.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-version: 1.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-18 05:57:18 +00:00
Shizun Ge 3893a6bd09 add on pull request workflow 2025-04-17 22:52:07 -07:00
Shizun Ge 2cb5d7ba9c update to go 1.24.2 2025-04-17 22:49:40 -07:00
Shizun Ge 79e128509d Merge pull request #150 from shizunge/dependabot/github_actions/docker/build-push-action-6.11.0
Bump docker/build-push-action from 6.10.0 to 6.11.0
2025-01-15 09:28:13 -08:00
dependabot[bot] 2384728729 Bump docker/build-push-action from 6.10.0 to 6.11.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.10.0 to 6.11.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.10.0...v6.11.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-13 08:50:04 +00:00
Shizun Ge ea5a8c07c2 Merge pull request #149 from shizunge/dependabot/github_actions/docker/setup-buildx-action-3.8.0
Bump docker/setup-buildx-action from 3.7.1 to 3.8.0
2024-12-23 08:02:39 -06:00
dependabot[bot] 8f6b0989fe Bump docker/setup-buildx-action from 3.7.1 to 3.8.0
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.7.1 to 3.8.0.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3.7.1...v3.8.0)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-23 08:54:35 +00:00
Shizun Ge a1de063f4e Merge pull request #146 from shizunge/dependabot/github_actions/docker/build-push-action-6.10.0
Bump docker/build-push-action from 6.9.0 to 6.10.0
2024-12-03 16:59:33 -08:00
dependabot[bot] cd7d7f3958 Bump docker/build-push-action from 6.9.0 to 6.10.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.9.0 to 6.10.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.9.0...v6.10.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-02 08:15:51 +00:00
Shizun Ge 749be56be1 Merge pull request #144 from shizunge/dependabot/go_modules/github.com/golang/glog-1.2.3
Bump github.com/golang/glog from 1.2.2 to 1.2.3
2024-11-11 10:47:05 -08:00
dependabot[bot] 80c5a21de9 Bump github.com/golang/glog from 1.2.2 to 1.2.3
Bumps [github.com/golang/glog](https://github.com/golang/glog) from 1.2.2 to 1.2.3.
- [Release notes](https://github.com/golang/glog/releases)
- [Commits](https://github.com/golang/glog/compare/v1.2.2...v1.2.3)

---
updated-dependencies:
- dependency-name: github.com/golang/glog
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-11 08:08:40 +00:00
Shizun Ge 258491b433 Merge pull request #128 from master-hax/unix-socket
add unix socket support for prometheus
2024-11-04 14:24:53 -08:00
Vivek a6390a1433 fix log string 2024-11-04 13:02:59 -08:00
Vivek Revankar c3ae83da33 nit 2024-10-30 19:17:32 -07:00
Vivek Revankar aeb234fbbf refactor 2024-10-30 19:17:32 -07:00
Vivek Revankar 194abc817d address comment 2024-10-30 19:17:32 -07:00
Vivek Revankar 7e4883db8e add unix socket support for prometheus 2024-10-30 19:17:32 -07:00
Shizun Ge fb853625d1 Merge pull request #141 from shizunge/dependabot/go_modules/github.com/prometheus/client_golang-1.20.5
Bump github.com/prometheus/client_golang from 1.20.4 to 1.20.5
2024-10-21 13:20:43 -07:00
dependabot[bot] d88d47f023 Bump github.com/prometheus/client_golang from 1.20.4 to 1.20.5
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.4 to 1.20.5.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.20.4...v1.20.5)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-21 08:32:48 +00:00
Shizun Ge 72add4dec4 Merge pull request #139 from shizunge/dependabot/github_actions/docker/setup-buildx-action-3.7.1
Bump docker/setup-buildx-action from 3.6.1 to 3.7.1
2024-10-07 21:25:06 -07:00
Shizun Ge 628d323375 Merge pull request #138 from shizunge/dependabot/github_actions/docker/build-push-action-6.9.0
Bump docker/build-push-action from 6.7.0 to 6.9.0
2024-10-07 21:24:52 -07:00
dependabot[bot] 2dfe193e18 Bump docker/setup-buildx-action from 3.6.1 to 3.7.1
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.6.1 to 3.7.1.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3.6.1...v3.7.1)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-07 08:24:04 +00:00
dependabot[bot] 70b94370b8 Bump docker/build-push-action from 6.7.0 to 6.9.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.7.0 to 6.9.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.7.0...v6.9.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-07 08:24:02 +00:00
Shizun Ge 95d3735d43 Merge pull request #133 from shizunge/dependabot/go_modules/github.com/prometheus/client_golang-1.20.4
Bump github.com/prometheus/client_golang from 1.20.3 to 1.20.4
2024-09-23 08:17:00 -07:00
dependabot[bot] 38d3910c00 Bump github.com/prometheus/client_golang from 1.20.3 to 1.20.4
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.3 to 1.20.4.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.20.3...v1.20.4)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-23 08:06:27 +00:00
Shizun Ge 092bd9ea66 Merge pull request #130 from shizunge/dependabot/go_modules/github.com/prometheus/client_golang-1.20.3
Bump github.com/prometheus/client_golang from 1.20.2 to 1.20.3
2024-09-10 15:15:14 -07:00
dependabot[bot] ee4701bf79 Bump github.com/prometheus/client_golang from 1.20.2 to 1.20.3
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.2 to 1.20.3.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/v1.20.3/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.20.2...v1.20.3)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-09 08:14:26 +00:00
Shizun Ge 7b8ab54f66 Merge pull request #124 from shizunge/dependabot/go_modules/github.com/prometheus/client_golang-1.20.2
Bump github.com/prometheus/client_golang from 1.20.0 to 1.20.2
2024-08-26 06:59:46 -07:00
dependabot[bot] b9cb96f0ad Bump github.com/prometheus/client_golang from 1.20.0 to 1.20.2
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.0 to 1.20.2.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.20.0...v1.20.2)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-26 08:51:37 +00:00
Shizun Ge 75a971d960 Merge pull request #122 from shizunge/dependabot/go_modules/github.com/pierrre/geohash-1.1.2
Bump github.com/pierrre/geohash from 1.1.1 to 1.1.2
2024-08-19 09:57:10 -07:00
Shizun Ge 67899f1247 Merge branch 'main' into dependabot/go_modules/github.com/pierrre/geohash-1.1.2 2024-08-19 09:56:54 -07:00
Shizun Ge b1c0d15263 Merge pull request #123 from shizunge/dependabot/github_actions/docker/build-push-action-6.7.0
Bump docker/build-push-action from 6.6.1 to 6.7.0
2024-08-19 09:56:10 -07:00
Shizun Ge f2cb5b53bd Merge pull request #121 from shizunge/dependabot/go_modules/github.com/prometheus/client_golang-1.20.0
Bump github.com/prometheus/client_golang from 1.19.1 to 1.20.0
2024-08-19 09:55:53 -07:00
Shizun Ge 4532125d37 Merge pull request #98 from shizunge/dependabot/go_modules/google.golang.org/protobuf-1.33.0
Bump google.golang.org/protobuf from 1.31.0 to 1.33.0
2024-08-19 09:55:27 -07:00
Shizun Ge da95bd75d2 Merge branch 'main' into dependabot/go_modules/google.golang.org/protobuf-1.33.0 2024-08-19 09:47:36 -07:00
dependabot[bot] 4781e68d09 Bump docker/build-push-action from 6.6.1 to 6.7.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.6.1 to 6.7.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.6.1...v6.7.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-19 08:42:28 +00:00
dependabot[bot] ae892e5dc3 Bump github.com/pierrre/geohash from 1.1.1 to 1.1.2
Bumps [github.com/pierrre/geohash](https://github.com/pierrre/geohash) from 1.1.1 to 1.1.2.
- [Commits](https://github.com/pierrre/geohash/compare/v1.1.1...v1.1.2)

---
updated-dependencies:
- dependency-name: github.com/pierrre/geohash
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-19 08:31:25 +00:00
dependabot[bot] 22ad7dfb84 Bump github.com/prometheus/client_golang from 1.19.1 to 1.20.0
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.19.1 to 1.20.0.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.19.1...v1.20.0)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-19 08:31:17 +00:00
Shizun Ge 7af2d3b574 Merge pull request #117 from shizunge/dependabot/go_modules/github.com/golang/glog-1.2.2
Bump github.com/golang/glog from 1.2.0 to 1.2.2
2024-08-12 11:33:12 -07:00
dependabot[bot] f281c40f71 Bump github.com/golang/glog from 1.2.0 to 1.2.2
Bumps [github.com/golang/glog](https://github.com/golang/glog) from 1.2.0 to 1.2.2.
- [Release notes](https://github.com/golang/glog/releases)
- [Commits](https://github.com/golang/glog/compare/v1.2.0...v1.2.2)

---
updated-dependencies:
- dependency-name: github.com/golang/glog
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-12 18:18:51 +00:00
Shizun Ge d2905e810a Merge pull request #120 from shizunge/dependabot/github_actions/docker/build-push-action-6.6.1
Bump docker/build-push-action from 5.3.0 to 6.6.1
2024-08-12 11:18:25 -07:00
Shizun Ge a537cc6f0f Merge pull request #119 from shizunge/dependabot/github_actions/docker/setup-buildx-action-3.6.1
Bump docker/setup-buildx-action from 3.3.0 to 3.6.1
2024-08-12 11:18:15 -07:00
Shizun Ge bbc75ed999 Merge pull request #118 from shizunge/dependabot/github_actions/docker/login-action-3.3.0
Bump docker/login-action from 3.1.0 to 3.3.0
2024-08-12 11:18:05 -07:00
Shizun Ge 9ff475e1b6 Merge pull request #116 from shizunge/dependabot/go_modules/github.com/oschwald/geoip2-golang-1.11.0
Bump github.com/oschwald/geoip2-golang from 1.9.0 to 1.11.0
2024-08-12 11:17:44 -07:00
dependabot[bot] 3d806deff9 Bump docker/build-push-action from 5.3.0 to 6.6.1
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5.3.0 to 6.6.1.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5.3.0...v6.6.1)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-12 08:56:20 +00:00
dependabot[bot] 38110c5f00 Bump docker/setup-buildx-action from 3.3.0 to 3.6.1
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.3.0 to 3.6.1.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3.3.0...v3.6.1)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-12 08:56:18 +00:00
dependabot[bot] 9fde49bd5a Bump docker/login-action from 3.1.0 to 3.3.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.1.0 to 3.3.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3.1.0...v3.3.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-12 08:56:16 +00:00
dependabot[bot] 84b55e04b4 Bump github.com/oschwald/geoip2-golang from 1.9.0 to 1.11.0
Bumps [github.com/oschwald/geoip2-golang](https://github.com/oschwald/geoip2-golang) from 1.9.0 to 1.11.0.
- [Release notes](https://github.com/oschwald/geoip2-golang/releases)
- [Commits](https://github.com/oschwald/geoip2-golang/compare/v1.9.0...v1.11.0)

---
updated-dependencies:
- dependency-name: github.com/oschwald/geoip2-golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-12 08:09:46 +00:00
Shizun Ge 415eb05f61 Merge pull request #99 from shizunge/dependabot/github_actions/docker/build-push-action-5.3.0
Bump docker/build-push-action from 5.1.0 to 5.3.0
2024-08-11 20:24:21 -07:00
Shizun Ge 75e39ccb06 Merge pull request #104 from shizunge/dependabot/github_actions/docker/setup-buildx-action-3.3.0
Bump docker/setup-buildx-action from 3.0.0 to 3.3.0
2024-08-11 20:24:01 -07:00
Shizun Ge 6ab026bcd4 Merge pull request #101 from shizunge/dependabot/github_actions/docker/login-action-3.1.0
Bump docker/login-action from 3.0.0 to 3.1.0
2024-08-11 20:23:51 -07:00
Shizun Ge b99ddbdb99 Merge pull request #110 from shizunge/dependabot/go_modules/github.com/prometheus/client_golang-1.19.1
Bump github.com/prometheus/client_golang from 1.18.0 to 1.19.1
2024-08-11 20:23:18 -07:00
dependabot[bot] 29e5975f5d Bump github.com/prometheus/client_golang from 1.18.0 to 1.19.1
Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.18.0 to 1.19.1.
- [Release notes](https://github.com/prometheus/client_golang/releases)
- [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prometheus/client_golang/compare/v1.18.0...v1.19.1)

---
updated-dependencies:
- dependency-name: github.com/prometheus/client_golang
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-13 08:30:05 +00:00
dependabot[bot] 656d436756 Bump docker/setup-buildx-action from 3.0.0 to 3.3.0
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.0.0 to 3.3.0.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3.0.0...v3.3.0)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-08 08:12:53 +00:00
dependabot[bot] fadf229e09 Bump docker/login-action from 3.0.0 to 3.1.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.0.0 to 3.1.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3.0.0...v3.1.0)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-18 08:25:51 +00:00
dependabot[bot] 220a8ce51d Bump docker/build-push-action from 5.1.0 to 5.3.0
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5.1.0 to 5.3.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5.1.0...v5.3.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-18 08:25:45 +00:00
dependabot[bot] d726b4673d Bump google.golang.org/protobuf from 1.31.0 to 1.33.0
Bumps google.golang.org/protobuf from 1.31.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-13 23:09:29 +00:00
Shizun Ge 7341b404af Merge pull request #91 from shizunge/dependabot/github_actions/peter-evans/dockerhub-description-4
Bump peter-evans/dockerhub-description from 3 to 4
2024-01-29 23:08:40 -08:00
Shizun Ge 890b9210c0 Merge pull request #92 from shizunge/prometheus
Prometheus roundup the trapped time to the interval
2024-01-29 23:08:30 -08:00
dependabot[bot] 50233633a5 Bump peter-evans/dockerhub-description from 3 to 4
Bumps [peter-evans/dockerhub-description](https://github.com/peter-evans/dockerhub-description) from 3 to 4.
- [Release notes](https://github.com/peter-evans/dockerhub-description/releases)
- [Commits](https://github.com/peter-evans/dockerhub-description/compare/v3...v4)

---
updated-dependencies:
- dependency-name: peter-evans/dockerhub-description
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-29 08:13:30 +00:00
Shizun Ge c309a8fc58 [readme] remove sudo 2024-01-28 21:52:12 -08:00
Shizun Ge 0cc52eee46 Prometheus roundup the trapped time to the interval.
In the old way, if the connection is broken less than an interval, the trapped time won't be reported.
With this fix, the prometheus should report the same value as the log.
2024-01-27 23:26:39 -08:00
Shizun Ge 8131751045 [workflows] on-push publishes to the development package. 2024-01-27 23:20:54 -08:00
Shizun Ge 56076bc107 [workflows] stop removing dev- images.
I don't think it remove the associated untagged arch specific images.
Until we find a way to keep or drop the entire package, we keep all of them.
2024-01-20 13:48:04 -08:00
Shizun Ge fbd60c320b remove endlessh-go binary 2024-01-20 00:11:10 -08:00
Shizun Ge 9a152ef3b3 Fix on-push.yml 2024-01-19 23:39:28 -08:00
Shizun Ge 11d0d8ac67 Do not delete untagged images.
These images could be the release images for different OS/Arch/
2024-01-19 23:38:29 -08:00
Shizun Ge 475b6b8ef8 Keep dev images for a week 2024-01-19 23:03:30 -08:00
Shizun Ge 44cd26db29 Merge pull request #86 from shizunge/prometheus
Multiple ports and clean metrics
2024-01-19 10:04:13 -08:00
Shizun Ge 6e7015b3eb [readme] update label of the metrics 2024-01-18 23:18:34 -08:00
Shizun Ge 54f5aa75e5 [dashboard] fix current connections 2024-01-18 22:58:35 -08:00
Shizun Ge e395971cfd clean metrics, remove series if the ip is not seen for a while. 2024-01-18 22:58:35 -08:00
Shizun Ge 37d428cdf5 add local_port label to all metrics 2024-01-18 22:58:35 -08:00
Shizun Ge 7da8e5e9ab update documents about multiple ports 2024-01-18 22:58:35 -08:00
Shizun Ge fee1f1a67d re-org files into packages. update copyright. accept multiple ports. 2024-01-18 22:58:35 -08:00
Shizun Ge df4cd39c57 refactor: move prometheus outside client class 2024-01-18 22:58:35 -08:00
Shizun Ge 2c0ee146ee [workflow] exclude dashboard and examples from on-push trigger. 2024-01-18 22:58:00 -08:00
Shizun Ge 4eaab6b0e0 [workflows] build container image on other branches and workflow_dispatch. 2024-01-18 20:13:05 -08:00
29 changed files with 1339 additions and 448 deletions
+2 -2
View File
@@ -12,9 +12,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Update Docker Hub description
uses: peter-evans/dockerhub-description@v3
uses: peter-evans/dockerhub-description@v5
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
+66
View File
@@ -0,0 +1,66 @@
name: On pull request
on:
pull_request:
branches:
- 'main'
paths-ignore:
- 'dashboard/*'
- 'examples/*'
- 'README.md'
- 'LICENSE'
workflow_dispatch:
env:
PLATFORMS: "linux/amd64,linux/arm64,linux/arm/v7"
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: '1.26.1'
cache: true
- name: Install dependencies
run: go mod download
- name: Run Tests
run: go test -v ./...
build_container_image:
name: Build Docker image
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4.1.0
- name: Docker meta
id: meta
uses: docker/metadata-action@v6
with:
images: |
ghcr.io/${{ github.repository }}-development
tags: |
type=raw,value=dev-{{date 'X'}}
type=raw,value=latest
type=ref,event=branch
type=edge,branch=main
- name: Build
uses: docker/build-push-action@v7.2.0
with:
platforms: ${{ env.PLATFORMS }}
push: false
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
provenance: false
-80
View File
@@ -1,80 +0,0 @@
name: On push to main
on:
push:
branches:
- main
env:
PLATFORMS: "linux/amd64,linux/arm64,linux/arm/v7"
jobs:
build_and_push:
name: Build and push Docker image
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.0.0
- name: Login to docker hub
uses: docker/login-action@v3.0.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3.0.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ github.token }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ github.repository }}
ghcr.io/${{ github.repository }}
tags: |
type=raw,value=dev-{{date 'X'}}
type=raw,value=development
type=ref,event=branch
type=edge,branch=main
- name: Build and push ${{ github.repository }}:${{ steps.git.outputs.image_tag }}
uses: docker/build-push-action@v5.1.0
with:
platforms: ${{ env.PLATFORMS }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
provenance: false
clean-ghcr:
name: Delete old dev container images
runs-on: ubuntu-latest
steps:
- name: Delete old dev images
uses: snok/container-retention-policy@v2
with:
image-names: endlessh-go
cut-off: One day ago UTC
account-type: personal
token: ${{ secrets.TOKEN_DELETE_GHCR_IMAGES }}
keep-at-least: 5
skip-tags: latest, development
filter-tags: "dev-*"
dry-run: False
- name: Delete untagged images
uses: snok/container-retention-policy@v2
with:
image-names: endlessh-go
cut-off: One hour ago UTC
account-type: personal
token: ${{ secrets.TOKEN_DELETE_GHCR_IMAGES }}
keep-at-least: 0
untagged-only: True
skip-tags: latest, development
dry-run: False
+79
View File
@@ -0,0 +1,79 @@
name: On push
on:
push:
branches-ignore:
- 'release'
- 'dependabot/**'
paths-ignore:
- 'dashboard/*'
- 'examples/*'
- 'README.md'
- 'LICENSE'
workflow_dispatch:
env:
PLATFORMS: "linux/amd64,linux/arm64,linux/arm/v7"
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: '1.26.1'
cache: true
- name: Install dependencies
run: go mod download
- name: Run Tests
run: go test -v ./...
build_and_push:
name: Build and push Docker image
runs-on: ubuntu-latest
if: ${{ github.actor != 'dependabot[bot]' }}
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4.1.0
- name: Login to Docker Hub
uses: docker/login-action@v4.2.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v4.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ github.token }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v6
with:
images: |
${{ github.repository }}-development
ghcr.io/${{ github.repository }}-development
tags: |
type=raw,value=dev-{{date 'X'}}
type=raw,value=latest
type=ref,event=branch
type=edge,branch=main
- name: Build and push ${{ github.repository }}:${{ steps.git.outputs.image_tag }}
uses: docker/build-push-action@v7.2.0
with:
platforms: ${{ env.PLATFORMS }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
provenance: false
+7 -7
View File
@@ -13,25 +13,25 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3.0.0
uses: docker/setup-buildx-action@v4.1.0
- name: Login to docker hub
uses: docker/login-action@v3.0.0
uses: docker/login-action@v4.2.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3.0.0
uses: docker/login-action@v4.2.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ github.token }}
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: |
${{ github.repository }}
@@ -40,7 +40,7 @@ jobs:
type=ref,event=branch
type=ref,event=tag
- name: Build and push
uses: docker/build-push-action@v5.1.0
uses: docker/build-push-action@v7.2.0
with:
platforms: ${{ env.PLATFORMS }}
push: true
+1
View File
@@ -0,0 +1 @@
endlessh-go
+23 -6
View File
@@ -1,5 +1,12 @@
# endlessh-go
[![Release](https://img.shields.io/github/release/shizunge/endlessh-go.svg?label=Release)](https://github.com/shizunge/endlessh-go/releases/latest)
[![License](https://img.shields.io/badge/License-GPLv3-blue)](https://github.com/shizunge/endlessh-go/blob/main/LICENSE)
[![Image Size](https://img.shields.io/docker/image-size/shizunge/endlessh-go/latest.svg?label=Image%20Size)](https://hub.docker.com/r/shizunge/endlessh-go)
[![Docker Pulls](https://img.shields.io/docker/pulls/shizunge/endlessh-go.svg?label=Docker%20Pulls&logo=Docker)](https://hub.docker.com/r/shizunge/endlessh-go)
[![Build](https://img.shields.io/github/actions/workflow/status/shizunge/endlessh-go/on-push.yml?label=Build&branch=main&logo=GitHub)](https://github.com/shizunge/endlessh-go/actions/workflows/on-push.yml)
[![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/shizunge/endlessh-go?label=CodeFactor&logo=CodeFactor)](https://www.codefactor.io/repository/github/shizunge/endlessh-go)
A golang implementation of [endlessh](https://nullprogram.com/blog/2019/03/22/) exporting Prometheus metrics, visualized by a Grafana dashboard.
![screenshot](https://github.com/shizunge/endlessh-go/raw/main/dashboard/screenshot.png)
@@ -22,7 +29,7 @@ go build .
Alternatively, you can use the [docker image](https://hub.docker.com/r/shizunge/endlessh-go):
```
sudo docker run -d -p 2222:2222 shizunge/endlessh-go -logtostderr -v=1
docker run -d -p 2222:2222 shizunge/endlessh-go -logtostderr -v=1
```
It listens to port `2222` by default.
@@ -61,22 +68,32 @@ Usage of ./endlessh-go
when logging hits line file:N, emit a stack trace
-log_dir string
If non-empty, write log files in this directory
-log_link string
If non-empty, add symbolic links in this directory to the log files
-logbuflevel int
Buffer log messages logged at this level or lower (-1 means don't buffer; 0 means buffer INFO only; ...). Has limited applicability on non-prod platforms.
-logtostderr
log to standard error instead of files
-max_clients int
Maximum number of clients (default 4096)
-max_mind_db string
Path to the MaxMind DB file.
-port string
SSH listening port (default "2222")
-port value
SSH listening port. You may provide multiple -port flags to listen to multiple ports. (default "2222")
-prometheus_clean_unseen_seconds int
Remove series if the IP is not seen for the given time. Set to 0 to disable. (default 0)
-prometheus_entry string
Entry point for prometheus (default "metrics")
-prometheus_host string
The address for prometheus (default "0.0.0.0")
-prometheus_port string
The port for prometheus (default "2112")
-proxy_protocol_enabled
Enable PROXY protocol support. This causes the server to expect PROXY protocol headers on incoming connections.
-proxy_protocol_read_header_timeout_ms int
Timeout for reading the PROXY protocol header in milliseconds. If the connection does not send a valid PROXY protocol header in this time, the header is ignored. (default 200)
-stderrthreshold value
logs at or above this threshold go to stderr
logs at or above this threshold go to stderr (default 2)
-v value
log level for V logs
-vmodule value
@@ -93,8 +110,8 @@ Endlessh-go exports the following Prometheus metrics.
| endlessh_client_closed_count_total | count | Total number of clients that stopped connecting to this host. |
| endlessh_sent_bytes_total | count | Total bytes sent to clients that tried to connect to this host. |
| endlessh_trapped_time_seconds_total | count | Total seconds clients spent on endlessh. |
| endlessh_client_open_count | count | Number of connections of clients. <br> Labels: <br> <ul><li> `ip`: IP of the client </li> <li> `country`: Country of the IP </li> <li> `location`: Country, Region, and City </li> <li> `geohash`: Geohash of the location </li></ul> |
| endlessh_client_trapped_time_seconds | count | Seconds a client spends on endlessh. <br> Labels: <br> <ul><li> `ip`: IP of the client </li></ul> |
| endlessh_client_open_count | count | Number of connections of clients. <br> Labels: <br> <ul><li> `ip`: Remote IP of the client </li> <li> `local_port`: Local port the program listens to </li> <li> `country`: Country of the IP </li> <li> `location`: Country, Region, and City </li> <li> `geohash`: Geohash of the location </li></ul> |
| endlessh_client_trapped_time_seconds | count | Seconds a client spends on endlessh. <br> Labels: <br> <ul><li> `ip`: Remote IP of the client </li> <li> `local_port`: Local port the program listens to </li></ul> |
The metrics is off by default, you can turn it via the CLI argument `-enable_prometheus`.
-111
View File
@@ -1,111 +0,0 @@
// Copyright (C) 2021 Shizun Ge
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
package main
import (
"math/rand"
"net"
"sync/atomic"
"time"
"github.com/golang/glog"
"github.com/prometheus/client_golang/prometheus"
)
var letterBytes = []byte(" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890!@#$%^&*()-=_+[]{}|;:',./<>?")
func randStringBytes(n int64) []byte {
b := make([]byte, n+1)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
b[n] = '\n'
return b
}
type client struct {
conn net.Conn
last time.Time
next time.Time
start time.Time
interval time.Duration
geoipSupplier string
geohash string
country string
location string
bytesSent int
prometheusEnabled bool
}
func NewClient(conn net.Conn, interval time.Duration, maxClient int64, geoipSupplier string, prometheusEnabled bool) *client {
addr := conn.RemoteAddr().(*net.TCPAddr)
atomic.AddInt64(&numCurrentClients, 1)
atomic.AddInt64(&numTotalClients, 1)
geohash, country, location, err := geohashAndLocation(addr.IP.String(), geoipSupplier)
if err != nil {
glog.Warningf("Failed to obatin the geohash of %v: %v.", addr.IP, err)
}
if prometheusEnabled {
clientIP.With(prometheus.Labels{
"ip": addr.IP.String(),
"geohash": geohash,
"country": country,
"location": location}).Inc()
}
glog.V(1).Infof("ACCEPT host=%v port=%v n=%v/%v\n", addr.IP, addr.Port, numCurrentClients, maxClient)
return &client{
conn: conn,
last: time.Now(),
next: time.Now().Add(interval),
start: time.Now(),
interval: interval,
geohash: geohash,
country: country,
location: location,
bytesSent: 0,
prometheusEnabled: prometheusEnabled,
}
}
func (c *client) Send(bannerMaxLength int64) error {
defer func(c *client) {
addr := c.conn.RemoteAddr().(*net.TCPAddr)
millisecondsSpent := time.Now().Sub(c.last).Milliseconds()
c.last = time.Now()
c.next = time.Now().Add(c.interval)
atomic.AddInt64(&numTotalMilliseconds, millisecondsSpent)
if c.prometheusEnabled {
clientSeconds.With(prometheus.Labels{"ip": addr.IP.String()}).Add(float64(millisecondsSpent) / 1000)
}
}(c)
length := rand.Int63n(bannerMaxLength)
bytesSent, err := c.conn.Write(randStringBytes(length))
if err != nil {
return err
}
c.bytesSent += bytesSent
atomic.AddInt64(&numTotalBytes, int64(bytesSent))
return nil
}
func (c *client) Close() {
addr := c.conn.RemoteAddr().(*net.TCPAddr)
atomic.AddInt64(&numCurrentClients, -1)
atomic.AddInt64(&numTotalClientsClosed, 1)
glog.V(1).Infof("CLOSE host=%v port=%v time=%v bytes=%v\n", addr.IP, addr.Port, time.Now().Sub(c.start).Seconds(), c.bytesSent)
c.conn.Close()
}
+123
View File
@@ -0,0 +1,123 @@
// Copyright (C) 2021-2026 Shizun Ge
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
package client
import (
"math/rand"
"net"
"strconv"
"sync/atomic"
"time"
"github.com/golang/glog"
)
var (
numCurrentClients int64
letterBytes = []byte(" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890!@#$%^&*()-=_+[]{}|;:',./<>?")
)
func randStringBytes(n int64) []byte {
b := make([]byte, n+1)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
b[n] = '\n'
return b
}
type Client struct {
conn net.Conn
next time.Time
start time.Time
last time.Time
interval time.Duration
bytesSent int
}
func NewClient(conn net.Conn, interval time.Duration, maxClients int64) *Client {
for numCurrentClients >= maxClients {
time.Sleep(interval)
}
atomic.AddInt64(&numCurrentClients, 1)
// Enable TCP keepalive to detect dead peers at the kernel level.
// This is a safety net for long intervals where the write deadline
// alone would be too slow to detect dead connections. For example,
// with interval=10min, without keepalive a ghost connection would
// go undetected for 10+ minutes.
// Keepalive cannot detect peers that are alive at the TCP level
// (kernel still responds to probes) but stalled at the application
// level — the write deadline in Send() covers that case.
// Detection time: ~idle + 9 probes (e.g. 10s + 9×10s ≈ 100s on Linux).
if tcpConn, ok := conn.(*net.TCPConn); ok {
tcpConn.SetKeepAlive(true)
keepalive := interval
if keepalive > 30*time.Second {
keepalive = 30 * time.Second
}
tcpConn.SetKeepAlivePeriod(keepalive)
}
addr := conn.RemoteAddr().(*net.TCPAddr)
glog.V(1).Infof("ACCEPT host=%v port=%v n=%v/%v\n", addr.IP, addr.Port, numCurrentClients, maxClients)
return &Client{
conn: conn,
next: time.Now().Add(interval),
start: time.Now(),
last: time.Now(),
interval: interval,
bytesSent: 0,
}
}
func (c *Client) RemoteIpAddr() string {
return c.conn.RemoteAddr().(*net.TCPAddr).IP.String()
}
func (c *Client) LocalPort() string {
return strconv.Itoa(c.conn.LocalAddr().(*net.TCPAddr).Port)
}
func (c *Client) Send(bannerMaxLength int64) (int, error) {
if time.Now().Before(c.next) {
time.Sleep(c.next.Sub(time.Now()))
}
c.next = time.Now().Add(c.interval)
length := rand.Int63n(bannerMaxLength)
// Set a write deadline to detect dead connections where the kernel
// buffers data but the remote peer is gone. Without this, Write()
// can succeed indefinitely on dead connections, causing goroutine leaks.
c.conn.SetWriteDeadline(time.Now().Add(c.interval))
bytesSent, err := c.conn.Write(randStringBytes(length))
if err != nil {
return 0, err
}
c.bytesSent += bytesSent
return bytesSent, nil
}
func (c *Client) MillisecondsSinceLast() int64 {
millisecondsSpent := time.Now().Sub(c.last).Milliseconds()
c.last = time.Now()
return millisecondsSpent
}
func (c *Client) Close() {
addr := c.conn.RemoteAddr().(*net.TCPAddr)
glog.V(1).Infof("CLOSE host=%v port=%v time=%v bytes=%v\n", addr.IP, addr.Port, time.Now().Sub(c.start).Seconds(), c.bytesSent)
c.conn.Close()
atomic.AddInt64(&numCurrentClients, -1)
}
+74 -43
View File
@@ -21,7 +21,7 @@
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "10.3.0-64399"
"version": "12.3.0-18356121373.patch9"
},
{
"type": "panel",
@@ -76,10 +76,9 @@
}
]
},
"description": "Dashboard for endlessh (Load metrics at the first panel instead of the last panel)",
"description": "Dashboard for endlessh (Add ports selection)",
"editable": false,
"fiscalYearStartMonth": 0,
"gnetId": 15156,
"graphTooltip": 0,
"id": null,
"links": [
@@ -108,7 +107,6 @@
"url": "https://grafana.com/grafana/dashboards/15156"
}
],
"liveNow": false,
"panels": [
{
"datasource": {
@@ -126,7 +124,7 @@
"steps": [
{
"color": "green",
"value": null
"value": 0
}
]
}
@@ -147,6 +145,7 @@
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
@@ -154,11 +153,12 @@
"fields": "/^Total number connections that endlessh trapped$/",
"values": false
},
"showPercentChange": false,
"text": {},
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "10.3.0-64399",
"pluginVersion": "12.3.0-18356121373.patch9",
"targets": [
{
"datasource": {
@@ -166,7 +166,7 @@
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "(endlessh_client_open_count{instance=~\"$host\",job=~\"$job\"} - endlessh_client_open_count{instance=~\"$host\",job=~\"$job\"} offset $__interval) > 0 or (endlessh_client_open_count{instance=~\"$host\",job=~\"$job\"}!=0 unless endlessh_client_open_count{instance=~\"$host\",job=~\"$job\"} offset $__interval)",
"expr": "(endlessh_client_open_count{instance=~\"$host\", local_port=~\"$port\",job=~\"$job\"} - endlessh_client_open_count{instance=~\"$host\",local_port=~\"$port\",job=~\"$job\"} offset $__interval) > 0 or (endlessh_client_open_count{instance=~\"$host\",local_port=~\"$port\",job=~\"$job\"}!=0 unless endlessh_client_open_count{instance=~\"$host\",local_port=~\"$port\",job=~\"$job\"} offset $__interval)",
"format": "table",
"instant": false,
"legendFormat": "Seen {{ip}}",
@@ -179,7 +179,7 @@
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"expr": "(endlessh_client_trapped_time_seconds{instance=~\"$host\",job=~\"$job\"} - endlessh_client_trapped_time_seconds{instance=~\"$host\",job=~\"$job\"} offset $__interval) > 0 or (endlessh_client_trapped_time_seconds{instance=~\"$host\",job=~\"$job\"}!=0 unless endlessh_client_trapped_time_seconds{instance=~\"$host\",job=~\"$job\"} offset $__interval)",
"expr": "(endlessh_client_trapped_time_seconds{instance=~\"$host\",local_port=~\"$port\",job=~\"$job\"} - endlessh_client_trapped_time_seconds{instance=~\"$host\",local_port=~\"$port\",job=~\"$job\"} offset $__interval) > 0 or (endlessh_client_trapped_time_seconds{instance=~\"$host\",local_port=~\"$port\",job=~\"$job\"}!=0 unless endlessh_client_trapped_time_seconds{instance=~\"$host\",local_port=~\"$port\",job=~\"$job\"} offset $__interval)",
"format": "table",
"hide": false,
"instant": false,
@@ -271,7 +271,7 @@
"steps": [
{
"color": "green",
"value": null
"value": 0
}
]
},
@@ -291,6 +291,7 @@
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
@@ -298,11 +299,12 @@
"fields": "/^Time spent on endlessh$/",
"values": false
},
"showPercentChange": false,
"text": {},
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "10.3.0-64399",
"pluginVersion": "12.3.0-18356121373.patch9",
"targets": [
{
"datasource": {
@@ -397,7 +399,7 @@
"steps": [
{
"color": "green",
"value": null
"value": 0
}
]
},
@@ -417,6 +419,7 @@
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
@@ -424,22 +427,25 @@
"fields": "",
"values": false
},
"showPercentChange": false,
"text": {},
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "10.3.0-64399",
"pluginVersion": "12.3.0-18356121373.patch9",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"exemplar": true,
"expr": "sum(increase(endlessh_sent_bytes_total{instance=~\"$host\",job=~\"$job\"}[$__range]))",
"expr": "sum(increase(endlessh_sent_bytes_total{instance=~\"$host\",local_port=~\"$port\",job=~\"$job\"}[$__range]))",
"hide": false,
"interval": "",
"legendFormat": "Bytes sent by endlessh",
"range": true,
"refId": "sent_bytes"
}
],
@@ -462,7 +468,7 @@
"steps": [
{
"color": "green",
"value": null
"value": 0
}
]
}
@@ -481,6 +487,7 @@
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
@@ -488,11 +495,12 @@
"fields": "/^Unique IPs connected$/",
"values": false
},
"showPercentChange": false,
"text": {},
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "10.3.0-64399",
"pluginVersion": "12.3.0-18356121373.patch9",
"targets": [
{
"datasource": {
@@ -576,7 +584,7 @@
"steps": [
{
"color": "green",
"value": null
"value": 0
}
]
}
@@ -595,6 +603,7 @@
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
@@ -602,11 +611,12 @@
"fields": "/^Client IP of the latest connection$/",
"values": false
},
"showPercentChange": false,
"text": {},
"textMode": "value",
"wideLayout": true
},
"pluginVersion": "10.3.0-64399",
"pluginVersion": "12.3.0-18356121373.patch9",
"targets": [
{
"datasource": {
@@ -712,7 +722,7 @@
"steps": [
{
"color": "green",
"value": null
"value": 0
},
{
"color": "#EAB839",
@@ -740,6 +750,7 @@
"graphMode": "none",
"justifyMode": "auto",
"orientation": "auto",
"percentChangeColorMode": "standard",
"reduceOptions": {
"calcs": [
"lastNotNull"
@@ -747,19 +758,21 @@
"fields": "",
"values": false
},
"showPercentChange": false,
"text": {},
"textMode": "auto",
"wideLayout": true
},
"pluginVersion": "10.3.0-64399",
"pluginVersion": "12.3.0-18356121373.patch9",
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
"editorMode": "code",
"exemplar": true,
"expr": "sum((endlessh_client_open_count_total{instance=~\"$host\",job=~\"$job\"}) - (endlessh_client_closed_count_total{instance=~\"$host\",job=~\"$job\"} offset $__interval or endlessh_client_open_count_total{instance=~\"$host\",job=~\"$job\"} * 0))",
"expr": "sum((endlessh_client_open_count_total{instance=~\"$host\",local_port=~\"$port\",job=~\"$job\"}) - (endlessh_client_closed_count_total{instance=~\"$host\",local_port=~\"$port\",job=~\"$job\"} or endlessh_client_open_count_total{instance=~\"$host\",local_port=~\"$port\",job=~\"$job\"} * 0))",
"instant": false,
"interval": "",
"legendFormat": "Open Connections",
@@ -786,6 +799,7 @@
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"barWidthFactor": 0.6,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
@@ -802,6 +816,7 @@
"type": "linear"
},
"showPoints": "auto",
"showValues": false,
"spanNulls": false,
"stacking": {
"group": "A",
@@ -812,13 +827,13 @@
}
},
"mappings": [],
"min": -0.01,
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
"value": 0
}
]
}
@@ -840,10 +855,12 @@
"showLegend": false
},
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.3.0-18356121373.patch9",
"targets": [
{
"datasource": {
@@ -904,11 +921,14 @@
"fields": "",
"values": false
},
"sort": "desc",
"tooltip": {
"hideZeros": false,
"mode": "single",
"sort": "none"
}
},
"pluginVersion": "12.3.0-18356121373.patch9",
"targets": [
{
"datasource": {
@@ -919,7 +939,7 @@
"refId": "A"
}
],
"title": "Connections by country",
"title": "Connections by Country",
"transformations": [
{
"id": "filterByRefId",
@@ -1015,7 +1035,7 @@
"steps": [
{
"color": "#96D98D",
"value": null
"value": 0
}
]
}
@@ -1029,7 +1049,6 @@
"y": 7
},
"id": 48,
"links": [],
"options": {
"basemap": {
"config": {},
@@ -1051,7 +1070,7 @@
"field": "Connections",
"fixed": "dark-green"
},
"fillOpacity": 0.4,
"fillOpacity": 0.8,
"shape": "circle",
"showLegend": false,
"size": {
@@ -1094,10 +1113,11 @@
"id": "zero",
"lat": 0,
"lon": 0,
"noRepeat": false,
"zoom": 1
}
},
"pluginVersion": "10.3.0-64399",
"pluginVersion": "12.3.0-18356121373.patch9",
"targets": [
{
"datasource": {
@@ -1194,6 +1214,9 @@
"type": "auto"
},
"filterable": true,
"footer": {
"reducers": []
},
"inspect": false,
"minWidth": 50
},
@@ -1204,7 +1227,7 @@
"steps": [
{
"color": "green",
"value": null
"value": 0
}
]
}
@@ -1271,14 +1294,6 @@
"id": 49,
"options": {
"cellHeight": "sm",
"footer": {
"countRows": false,
"fields": "",
"reducer": [
"sum"
],
"show": false
},
"frameIndex": 0,
"showHeader": true,
"sortBy": [
@@ -1288,7 +1303,7 @@
}
]
},
"pluginVersion": "10.3.0-64399",
"pluginVersion": "12.3.0-18356121373.patch9",
"targets": [
{
"datasource": {
@@ -1461,7 +1476,7 @@
}
],
"refresh": "",
"schemaVersion": 39,
"schemaVersion": 42,
"tags": [
"prometheus"
],
@@ -1475,7 +1490,6 @@
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values(endlessh_client_open_count_total, job)",
"hide": 0,
"includeAll": true,
"label": "Job",
"multi": true,
@@ -1487,7 +1501,6 @@
},
"refresh": 2,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
@@ -1499,7 +1512,6 @@
"uid": "${DS_PROMETHEUS}"
},
"definition": "label_values(endlessh_client_open_count_total{job=~\"$job\"}, instance)",
"hide": 0,
"includeAll": true,
"label": "Host",
"multi": true,
@@ -1511,7 +1523,26 @@
},
"refresh": 2,
"regex": "",
"skipUrlSync": false,
"sort": 1,
"type": "query"
},
{
"allValue": ".*",
"current": {},
"definition": "label_values(endlessh_client_open_count_total{job=~\"$job\", instance=~\"$host\"},local_port)",
"description": "",
"includeAll": true,
"label": "Port",
"multi": true,
"name": "port",
"options": [],
"query": {
"qryType": 1,
"query": "label_values(endlessh_client_open_count_total{job=~\"$job\", instance=~\"$host\"},local_port)",
"refId": "PrometheusVariableQueryEditor-VariableQuery"
},
"refresh": 2,
"regex": "",
"sort": 1,
"type": "query"
}
@@ -1525,6 +1556,6 @@
"timezone": "",
"title": "Endlessh",
"uid": "ATIxYkO7k",
"version": 6,
"version": 13,
"weekStart": ""
}
+324
View File
@@ -0,0 +1,324 @@
package main
import (
"bytes"
"fmt"
"net"
"os/exec"
"regexp"
"strings"
"sync"
"testing"
"time"
)
const (
waitForListenTimeout = 10 * time.Second
waitForConnectTimeout = 3 * time.Second
pollInterval = 50 * time.Millisecond
)
func waitForLogMatch(stderr *bytes.Buffer, pattern string, timeout time.Duration) bool {
re := regexp.MustCompile(pattern)
deadline := time.Now().Add(timeout)
for {
if time.Now().After(deadline) {
return false
}
if re.MatchString(stderr.String()) {
return true
}
time.Sleep(pollInterval)
}
}
func TestEndlesshIntegration_MultiplePorts(t *testing.T) {
const nPorts = 3
ports := make([]int, nPorts)
for i := 0; i < nPorts; i++ {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("failed to get free port: %v", err)
}
ports[i] = ln.Addr().(*net.TCPAddr).Port
ln.Close()
}
args := []string{"run", "main.go",
"-interval_ms=100",
"-max_clients=10",
"-logtostderr",
"-v=1",
}
for _, p := range ports {
args = append(args, fmt.Sprintf("-port=%d", p))
}
cmd := exec.Command("go", args...)
var stderr bytes.Buffer
cmd.Stderr = &stderr
if err := cmd.Start(); err != nil {
t.Fatalf("Failed to start server: %v", err)
}
defer func() {
if err := cmd.Process.Kill(); err != nil {
t.Logf("Failed to kill process: %v", err)
}
}()
if !waitForLogMatch(&stderr, "Listening on", waitForListenTimeout) {
t.Fatalf("Timeout waiting for server to start, got logs: %s", stderr.String())
}
for _, port := range ports {
addr := fmt.Sprintf("localhost:%d", port)
conn, err := net.Dial("tcp", addr)
if err != nil {
t.Fatalf("Failed to connect to server on port %d: %v", port, err)
}
if !waitForLogMatch(&stderr, `ACCEPT host=(127\.0\.0\.1|::1)`, waitForConnectTimeout) {
t.Errorf("Never saw any ACCEPT log, got logs: %s", stderr.String())
}
conn.Close()
if !waitForLogMatch(&stderr, `CLOSE host=(127\.0\.0\.1|::1)`, waitForConnectTimeout) {
t.Errorf("Never saw any CLOSE log, got logs: %s", stderr.String())
}
}
}
func TestEndlesshIntegration_TarpitBehavior(t *testing.T) {
var stderr bytes.Buffer
cmd := exec.Command("go", "run", "main.go", "-port=0", "-interval_ms=5000", "-max_clients=10", "-logtostderr", "-v=1")
cmd.Stderr = &stderr
if err := cmd.Start(); err != nil {
t.Fatalf("Failed to start server: %v", err)
}
defer func() {
if err := cmd.Process.Kill(); err != nil {
t.Logf("Failed to kill process: %v", err)
}
}()
if !waitForLogMatch(&stderr, "Listening on", waitForListenTimeout) {
t.Fatalf("Timeout waiting for server to start, got logs: %s", stderr.String())
}
stderrOutput := stderr.String()
re := regexp.MustCompile(`Listening on .*:(\d+)`)
m := re.FindStringSubmatch(stderrOutput)
if len(m) != 2 {
t.Fatalf("Could not parse port from logs: %s", stderrOutput)
}
port := m[1]
addr := "localhost:" + port
conn, err := net.Dial("tcp", addr)
if err != nil {
t.Fatalf("Failed to connect to server on port %s: %v", port, err)
}
defer conn.Close()
// Simulate SSH client banner
// Connect & send client banner
_, err = conn.Write([]byte("SSH-2.0-OpenSSH_8.2p1\r\n"))
if err != nil {
t.Fatalf("Write failed: %v", err)
}
// Expect FIRST LINE immediately (no delay)
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil || n == 0 {
t.Fatalf("Expected first tarpit line immediately, got: %v (%d bytes)", err, n)
}
t.Logf("Got first tarpit line (%d bytes): %q", n, buf[:n])
time.Sleep(100 * time.Millisecond)
conn.SetReadDeadline(time.Now().Add(1 * time.Second))
n2, err := conn.Read(buf)
if err == nil && n2 > 0 {
t.Errorf("Got %d bytes too soon (within 500ms), tarpit failed", n2)
}
}
func TestEndlesshIntegration_Concurrency(t *testing.T) {
maxClients := 5
var stderr bytes.Buffer
cmd := exec.Command("go", "run", "main.go", "-port=0", "-interval_ms=1000", fmt.Sprintf("-max_clients=%d", maxClients), "-logtostderr", "-v=1")
cmd.Stderr = &stderr
if err := cmd.Start(); err != nil {
t.Fatalf("Failed to start server: %v", err)
}
defer func() {
if err := cmd.Process.Kill(); err != nil {
t.Logf("Failed to kill process: %v", err)
}
}()
if !waitForLogMatch(&stderr, "Listening on", waitForListenTimeout) {
t.Fatalf("Timeout waiting for server to start, got logs: %s", stderr.String())
}
stderrOutput := stderr.String()
re := regexp.MustCompile(`Listening on .*:(\d+)`)
m := re.FindStringSubmatch(stderrOutput)
if len(m) != 2 {
t.Fatalf("Could not parse port from logs: %s", stderrOutput)
}
port := m[1]
addr := fmt.Sprintf("localhost:%s", port)
// Test multiple connections
var wg sync.WaitGroup
var mu sync.Mutex
activeClients := 0
maxActiveClients := 0
//sixthClientFailed := false
successfulReads := 0
for i := 0; i < maxClients+1; i++ {
wg.Add(1)
go func(clientID int) {
defer wg.Done()
conn, dialErr := net.Dial("tcp", addr)
if dialErr != nil {
if clientID == maxClients {
//sixthClientFailed = true
t.Logf("Client %d dial failed (expected): %v", clientID, dialErr)
} else {
t.Errorf("Client %d dial failed (unexpected): %v", clientID, dialErr)
}
return
}
defer conn.Close()
_, writeErr := conn.Write([]byte("SSH-2.0-OpenSSH_8.2p1\r\n"))
if writeErr != nil {
t.Logf("Client %d write failed: %v", clientID, writeErr)
return
}
buf := make([]byte, 1024)
conn.SetReadDeadline(time.Now().Add(3 * time.Second))
n1, readErr1 := conn.Read(buf)
if readErr1 != nil || n1 == 0 {
if clientID != maxClients { // only log unexpected failures
t.Logf("Client %d failed first tarpit line (unexpected): %v (%d bytes)", clientID, readErr1, n1)
}
return
}
// Client is active only if it successfully received data
mu.Lock()
activeClients++
if activeClients > maxActiveClients {
maxActiveClients = activeClients
}
successfulReads++
mu.Unlock()
t.Logf("Client %d got line 1 (%d bytes): %q", clientID, n1, buf[:n1])
// Keep the connection open for a while
time.Sleep(5 * time.Second)
mu.Lock()
activeClients--
mu.Unlock()
}(i)
time.Sleep(200 * time.Millisecond)
}
wg.Wait()
mu.Lock()
deferredSuccessfulReads := successfulReads
mu.Unlock()
if deferredSuccessfulReads < 1 {
t.Errorf("Expected at least one client to receive a tarpit line, got %d", deferredSuccessfulReads)
}
// Check if maxActiveClients exceeded maxClients
if maxActiveClients > maxClients {
t.Errorf("Expected max %d concurrent clients, got %d", maxClients, maxActiveClients)
}
// Check if the 6th client failed
/*mu.Lock()
if !sixthClientFailed {
t.Errorf("Expected 6th client to fail, but it succeeded")
}
mu.Unlock()
*/
// The 6th client does not necessarily fail at Dial because max_clients is
// enforced at the protocol/Read stage instead of at Accept.
//
// TODO: Enforce max_clients at Accept so the N+1 client fails fast at Dial.
}
func TestEndlesshIntegration_PrometheusMetrics(t *testing.T) {
var stderr bytes.Buffer
cmd := exec.Command(
"go", "run", "main.go",
"-port=0",
"-enable_prometheus",
"-prometheus_port=0",
"-interval_ms=100",
"-logtostderr", "-v=1",
)
cmd.Stderr = &stderr
if err := cmd.Start(); err != nil {
t.Fatalf("Failed to start server: %v", err)
}
defer cmd.Process.Kill()
if !waitForLogMatch(&stderr, "Starting Prometheus", waitForListenTimeout) {
t.Fatalf("Prometheus did not start: %s", stderr.String())
}
reProm := regexp.MustCompile(`Prometheus on IP port .*:(\d+)`)
reMain := regexp.MustCompile(`Listening on .*:(\d+)`)
promMatch := reProm.FindStringSubmatch(stderr.String())
mainMatch := reMain.FindStringSubmatch(stderr.String())
if len(promMatch) < 2 || len(mainMatch) < 2 {
t.Fatalf("Could not parse ports: %s", stderr.String())
}
promPort := promMatch[1]
mainPort := mainMatch[1]
conn, err := net.Dial("tcp", "localhost:"+mainPort)
if err != nil {
t.Fatalf("Dial failed: %v", err)
}
defer conn.Close()
conn.Write([]byte("SSH-2.0-test\r\n"))
time.Sleep(500 * time.Millisecond)
// Fetch metrics
resp, err := net.Dial("tcp", "localhost:"+promPort)
if err != nil {
t.Fatalf("Failed to connect to metrics endpoint: %v", err)
}
fmt.Fprintf(resp, "GET /metrics HTTP/1.1\r\nHost: localhost\r\n\r\n")
buf := make([]byte, 8192)
n, _ := resp.Read(buf)
body := string(buf[:n])
if !strings.Contains(body, "endlessh_client_open_count_total") {
t.Errorf("Missing expected metric in output:\n%s", body)
}
if !strings.Contains(body, "endlessh_sent_bytes_total") {
t.Errorf("Expected bytes metric not found:\n%s", body)
}
}
+5
View File
@@ -10,7 +10,12 @@ An example how to setup endlessh-go, Prometheus, and Grafana using [docker compo
An example how to setup endlessh-go with the Maxmind GeoIP Database.
## [kustomize-simple](./kustomize-simple)
An example how to setup endlessh-go using [kustomize](https://kustomize.io/).
## FAQ
### Bind to privileged ports (<1024) in a container
You need to add capability `NET_BIND_SERVICE` to the program.
+2 -2
View File
@@ -5,12 +5,12 @@ This is an example how to setup endlessh-go with the Maxmind GeoIP Database usin
To start the stack, in the _examples_ folder, run:
```
sudo docker-compose up -d
docker-compose up -d
```
The GeoIP Database will be saved in a mounted volume in: `./geo-data`. And the endlessh-go container will use this database to do the location lookups.
This example exposes the following ports. Except the SSH port, you should not expose other ports to public without protections (not included in this example) in production.
- **2222**: The SSH port. You may test endlessh-go by running `ssh -p 2222 localhost`. Your SSH client should hang. View the log of endlessh-go by running `sudo docker logs endlessh`.
- **2222**: The SSH port. You may test endlessh-go by running `ssh -p 2222 localhost`. Your SSH client should hang. View the log of endlessh-go by running `docker logs endlessh`.
- **2112**: The Prometheus metrics exported by endlessh-go. Go to [http://localhost:2112/metrics](http://localhost:2112/metrics) in your web browser to view the metrics.
@@ -1,4 +1,3 @@
version: "3"
services:
endlessh:
+2 -2
View File
@@ -9,12 +9,12 @@ This is an example how to setup endlessh-go, Prometheus, and Grafana using [dock
To start the stack, in the *examples* folder, run:
```
sudo docker-compose up -d
docker-compose up -d
```
This example exposes the following ports. Except the SSH port, you should not expose other ports to public without protections (not included in this example) in production.
* **2222**: The SSH port. You may test endlessh-go by running `ssh -p 2222 localhost`. Your SSH client should hang. View the log of endlessh-go by running `sudo docker logs endlessh`.
* **2222**: The SSH port. You may test endlessh-go by running `ssh -p 2222 localhost`. Your SSH client should hang. View the log of endlessh-go by running `docker logs endlessh`.
* **2112**: The Prometheus metrics exported by endlessh-go. Go to [http://localhost:2112/metrics](http://localhost:2112/metrics) in your web browser to view the metrics.
* **9090**: Prometheus web interface. Go to [http://localhost:9090](http://localhost:9090) in your web browser for Prometheus. You can check whether the target of endlessh-go is up (Click Status, then Targets).
* **3000**: Grafana. Go to [http://localhost:3000](http://localhost:3000) in your web browser for Grafana. Use username *examples* and password *examples* to login.
@@ -1,4 +1,3 @@
version: '3.5'
services:
endlessh:
+25
View File
@@ -0,0 +1,25 @@
## kustomize
This is an example how to setup endlessh-go with existing Prometheus and Grafana using [kustomize](https://kustomize.io/).
This example assumes the cluster already has a Prometheus Operator based monitoring stack. It deploys:
- endlessh-go
- a Service exposing SSH and Prometheus metrics
- a `ServiceMonitor` for scraping endlessh-go metrics
- a Grafana dashboard `ConfigMap`
To deploy the stack, run:
```bash
kubectl apply -k examples/kustomize-simple
```
`dashboard.json` is added to a `ConfigMap` with label `grafana_dashboard=1`, which can be picked up by a Grafana sidecar based dashboard loader.
The `ServiceMonitor` in `monitor.yaml` scrapes the `metrics` port every `60s`. If your Prometheus stack only selects `ServiceMonitor` objects with specific labels, add the matching label in `kustomization.yaml`.
The `endlessh` Service exposes the following ports inside the cluster:
- **22**: SSH for endlessh-go
- **2112**: Prometheus metrics exported by endlessh-go
File diff suppressed because one or more lines are too long
+31
View File
@@ -0,0 +1,31 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: endlessh
spec:
replicas: 1
template:
spec:
automountServiceAccountToken: false
containers:
- name: endlessh
image: shizunge/endlessh-go:latest
args:
- -interval_ms=1000
- -logtostderr
- -v=1
- -enable_prometheus
- -geoip_supplier=ip-api
- -host=[::]
- -prometheus_host=[::]
ports:
- name: ssh
containerPort: 2222
- name: metrics
containerPort: 2112
securityContext:
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
@@ -0,0 +1,21 @@
resources:
- deployment.yaml
- service.yaml
- monitor.yaml
configMapGenerator:
- name: endlessh-dashboard
files:
- dashboard.json
options:
labels:
grafana_dashboard: "1"
labels:
- pairs:
app.kubernetes.io/name: endlessh
includeSelectors: true
includeTemplates: true
fields:
- group: monitoring.coreos.com
kind: ServiceMonitor
path: spec/selector/matchLabels
create: true
+10
View File
@@ -0,0 +1,10 @@
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: endlessh
spec:
endpoints:
- interval: 60s
path: /metrics
port: metrics
jobLabel: app.kubernetes.io/name
+14
View File
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: endlessh
spec:
ports:
- name: ssh
port: 22
targetPort: ssh
protocol: TCP
- name: metrics
port: 2112
targetPort: metrics
protocol: TCP
+4 -4
View File
@@ -1,4 +1,4 @@
// Copyright (C) 2023 Shizun Ge
// Copyright (C) 2023-2026 Shizun Ge
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -14,16 +14,16 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
package coordinates
package geoip
// Map country's ISO to their capital's latitude and longitude.
// Country's ISO see https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
type Location struct {
type location struct {
Latitude float64
Longitude float64
}
var Country = map[string]Location{
var countryToLocation = map[string]location{
"AD": {42.5, 1.5},
"AE": {24.4511, 54.3969},
"AF": {34.5328, 69.1658},
+18 -19
View File
@@ -1,4 +1,4 @@
// Copyright (C) 2021-2023 Shizun Ge
// Copyright (C) 2021-2026 Shizun Ge
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -14,7 +14,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
package main
package geoip
import (
"encoding/json"
@@ -24,15 +24,14 @@ import (
"net/http"
"strings"
"endlessh-go/coordinates"
"github.com/oschwald/geoip2-golang"
"github.com/pierrre/geohash"
)
var (
maxMindDbFileName *string
)
type GeoOption struct {
GeoipSupplier string
MaxMindDbFileName string
}
func composeLocation(country string, region string, city string) string {
var locations []string
@@ -69,9 +68,9 @@ type ipapi struct {
Longitude float64 `json:"lon"`
}
func geohashAndLocationFromIpapi(address string) (string, string, string, error) {
func geohashAndLocationFromIpapi(ipAddr string) (string, string, string, error) {
var geo ipapi
response, err := http.Get("http://ip-api.com/json/" + address)
response, err := http.Get("http://ip-api.com/json/" + ipAddr)
if err != nil {
return "s000", "Unknown", "Unknown", err
}
@@ -88,7 +87,7 @@ func geohashAndLocationFromIpapi(address string) (string, string, string, error)
}
if geo.Status != "success" {
return "s000", "Unknown", "Unknown", fmt.Errorf("failed to query %v via ip-api: status: %v, message: %v", address, geo.Status, geo.Message)
return "s000", "Unknown", "Unknown", fmt.Errorf("failed to query %v via ip-api: status: %v, message: %v", ipAddr, geo.Status, geo.Message)
}
gh := geohash.EncodeAuto(geo.Latitude, geo.Longitude)
@@ -98,14 +97,14 @@ func geohashAndLocationFromIpapi(address string) (string, string, string, error)
return gh, country, location, nil
}
func geohashAndLocationFromMaxMindDb(address string) (string, string, string, error) {
db, err := geoip2.Open(*maxMindDbFileName)
func geohashAndLocationFromMaxMindDb(ipAddr, maxMindDbFileName string) (string, string, string, error) {
db, err := geoip2.Open(maxMindDbFileName)
if err != nil {
return "s000", "Unknown", "Unknown", err
}
defer db.Close()
// If you are using strings that may be invalid, check that ip is not nil
ip := net.ParseIP(address)
ip := net.ParseIP(ipAddr)
cityRecord, err := db.City(ip)
if err != nil {
return "s000", "Unknown", "Unknown", err
@@ -117,7 +116,7 @@ func geohashAndLocationFromMaxMindDb(address string) (string, string, string, er
iso := cityRecord.Country.IsoCode
if latitude == 0 && longitude == 0 {
// In case of using Country DB, city is not available.
loc, ok := coordinates.Country[iso]
loc, ok := countryToLocation[iso]
if ok {
latitude = loc.Latitude
longitude = loc.Longitude
@@ -135,15 +134,15 @@ func geohashAndLocationFromMaxMindDb(address string) (string, string, string, er
return gh, country, location, nil
}
func geohashAndLocation(address string, geoipSupplier string) (string, string, string, error) {
switch geoipSupplier {
func GeohashAndLocation(ipAddr string, option GeoOption) (string, string, string, error) {
switch option.GeoipSupplier {
case "off":
return "s000", "Geohash off", "Geohash off", nil
case "ip-api":
return geohashAndLocationFromIpapi(address)
return geohashAndLocationFromIpapi(ipAddr)
case "max-mind-db":
return geohashAndLocationFromMaxMindDb(address)
return geohashAndLocationFromMaxMindDb(ipAddr, option.MaxMindDbFileName)
default:
return "s000", "Unknown", "Unknown", fmt.Errorf("unknown geoipSupplier %v.", geoipSupplier)
return "s000", "Unknown", "Unknown", fmt.Errorf("unknown geoipSupplier %v.", option.GeoipSupplier)
}
}
+16 -13
View File
@@ -1,22 +1,25 @@
module endlessh-go
go 1.20
go 1.26.1
require (
github.com/golang/glog v1.2.0
github.com/oschwald/geoip2-golang v1.9.0
github.com/pierrre/geohash v1.1.1
github.com/prometheus/client_golang v1.18.0
github.com/golang/glog v1.2.5
github.com/oschwald/geoip2-golang v1.13.0
github.com/pierrre/geohash v1.1.4
github.com/pires/go-proxyproto v0.12.0
github.com/prometheus/client_golang v1.23.2
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/oschwald/maxminddb-golang v1.11.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
golang.org/x/sys v0.15.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oschwald/maxminddb-golang v1.13.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
golang.org/x/sys v0.35.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
)
+65 -34
View File
@@ -1,45 +1,76 @@
github.com/Codefor/geohash v0.0.0-20140723084247-1b41c28e3a9d h1:iG9B49Q218F/XxXNRM7k/vWf7MKmLIS8AcJV9cGN4nA=
github.com/Codefor/geohash v0.0.0-20140723084247-1b41c28e3a9d/go.mod h1:RVnhzAX71far8Kc3TQeA0k/dcaEKUnTDSOyet/JCmGI=
github.com/TomiHiltunen/geohash-golang v0.0.0-20150112065804-b3e4e625abfb h1:wumPkzt4zaxO4rHPBrjDK8iZMR41C1qs7njNqlacwQg=
github.com/TomiHiltunen/geohash-golang v0.0.0-20150112065804-b3e4e625abfb/go.mod h1:QiYsIBRQEO+Z4Rz7GoI+dsHVneZNONvhczuA+llOZNM=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/broady/gogeohash v0.0.0-20120525094510-7b2c40d64042 h1:iEdmkrNMLXbM7ecffOAtZJQOQUTE4iMonxrb5opUgE4=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/broady/gogeohash v0.0.0-20120525094510-7b2c40d64042/go.mod h1:f1L9YvXvlt9JTa+A17trQjSMM6bV40f+tHjB+Pi+Fqk=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fanixk/geohash v0.0.0-20150324002647-c1f9b5fa157a h1:Fyfh/dsHFrC6nkX7H7+nFdTd1wROlX/FxEIWVpKYf1U=
github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
github.com/fanixk/geohash v0.0.0-20150324002647-c1f9b5fa157a/go.mod h1:UgNw+PTmmGN8rV7RvjvnBMsoTU8ZXXnaT3hYsDTBlgQ=
github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I=
github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mmcloughlin/geohash v0.10.0 h1:9w1HchfDfdeLc+jFEf/04D27KP7E2QmpDu52wPbJWRE=
github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc=
github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y=
github.com/oschwald/maxminddb-golang v1.11.0 h1:aSXMqYR/EPNjGE8epgqwDay+P30hCBZIveY0WZbAWh0=
github.com/oschwald/maxminddb-golang v1.11.0/go.mod h1:YmVI+H0zh3ySFR3w+oz8PCfglAFj3PuCmui13+P9zDg=
github.com/pierrre/assert v0.3.2 h1:wXdlkVN5FVSLEKl6pGijcCYkldgfjRgyheU3C1/by9Q=
github.com/pierrre/compare v1.4.2 h1:oabIiWclzAlXG7S/2MYSFDJ/vR34oa/MYrBZh5PNU80=
github.com/pierrre/geohash v1.1.1 h1:XCkvOyv/uesenMPhkvsCfIiUalBmGdHlFY0bIWTqb+s=
github.com/pierrre/geohash v1.1.1/go.mod h1:ucAm7cbgGBoVr6cr1t+d3ea5XQ9P5zKHXfS1Qy2iKVY=
github.com/pierrre/go-libs v0.2.14 h1:wAPoOrslKLnha6ow5EKkxxZpo76kOea57efs71A/ZnQ=
github.com/pierrre/pretty v0.0.10 h1:Cb5som+1EpU+x7UA5AMy9I8AY2XkzMBywkLEAdo1JDg=
github.com/mmcloughlin/geohash v0.10.0/go.mod h1:oNZxQo5yWJh0eMQEP/8hwQuVx9Z9tjwFUqcTB1SmG0c=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/oschwald/geoip2-golang v1.13.0 h1:Q44/Ldc703pasJeP5V9+aFSZFmBN7DKHbNsSFzQATJI=
github.com/oschwald/geoip2-golang v1.13.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
github.com/oschwald/maxminddb-golang v1.13.0 h1:R8xBorY71s84yO06NgTmQvqvTvlS/bnYZrrWX1MElnU=
github.com/oschwald/maxminddb-golang v1.13.0/go.mod h1:BU0z8BfFVhi1LQaonTwwGQlsHUEu9pWNdMfmq4ztm0o=
github.com/pierrre/assert v0.12.1 h1:Hg+r10601guGiOvXoWHx1Xp2TLj3w6FMb+PN7pR+iQc=
github.com/pierrre/assert v0.12.1/go.mod h1:9AEGGFuJp339PdEUkhfOq8zqYPdSurPWAua35EEpY2o=
github.com/pierrre/compare v1.4.14 h1:snH4S/2nClsCCgYAvseyQYX6RHX8WvCdd23deiL1ovc=
github.com/pierrre/compare v1.4.14/go.mod h1:5RkfHZojsCAFZR+mW9SHH55mH1tCWNWMP7xhWgxc6QE=
github.com/pierrre/geohash v1.1.4 h1:yzKGZnvToMhSorOzdR7dULzYkzc6BgEYN//yAn/sWsw=
github.com/pierrre/geohash v1.1.4/go.mod h1:acEkGYRKiLkhsU88AolKimmPzyBC7vqi9YUs0/LkKNI=
github.com/pierrre/go-libs v0.28.1 h1:PCz1fdKdSwCmwO5GMCN/L5qlvqxIBT54iKKzrbI1Nik=
github.com/pierrre/go-libs v0.28.1/go.mod h1:KXbqq+niFCQ48LPSjX2lKG1IdCoTBrTpurkVVDH2W8U=
github.com/pierrre/pretty v0.23.0 h1:LYCkefa+DV87cu/xqUnPh75x1T0zXgnHvAn7wW+OgN0=
github.com/pierrre/pretty v0.23.0/go.mod h1:ILYWjIqXAO9iLC2sDcHkgv2Vp0JIIKGMjRtwHAdOVAM=
github.com/pires/go-proxyproto v0.12.0 h1:TTCxD66dU898tahivkqc3hoceZp7P44FnorWyo9d5vM=
github.com/pires/go-proxyproto v0.12.0/go.mod h1:qUvfqUMEoX7T8g0q7TQLDnhMjdTrxnG0hvpMn+7ePNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/the42/cartconvert v1.0.0 h1:g8kt6ic2GEhdcZ61ZP9GsWwhosVo5nCnH1n2/oAQXUU=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
github.com/the42/cartconvert v1.0.0/go.mod h1:fWO/msnJVhHqN1yX6OBoxSyfj7TEj1hHiL8bJSQsK30=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+137 -123
View File
@@ -1,4 +1,4 @@
// Copyright (C) 2021-2023 Shizun Ge
// Copyright (C) 2021-2026 Shizun Ge
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -17,108 +17,134 @@
package main
import (
"endlessh-go/client"
"endlessh-go/geoip"
"endlessh-go/metrics"
"flag"
"fmt"
"math/rand"
"net"
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/golang/glog"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
proxyproto "github.com/pires/go-proxyproto"
)
var (
numCurrentClients int64
numTotalClients int64
numTotalClientsClosed int64
numTotalBytes int64
numTotalMilliseconds int64
totalClients prometheus.CounterFunc
totalClientsClosed prometheus.CounterFunc
totalBytes prometheus.CounterFunc
totalSeconds prometheus.CounterFunc
clientIP *prometheus.CounterVec
clientSeconds *prometheus.CounterVec
)
func initPrometheus(prometheusHost, prometheusPort, prometheusEntry string) {
totalClients = prometheus.NewCounterFunc(
prometheus.CounterOpts{
Name: "endlessh_client_open_count_total",
Help: "Total number of clients that tried to connect to this host.",
}, func() float64 {
return float64(numTotalClients)
},
)
totalClientsClosed = prometheus.NewCounterFunc(
prometheus.CounterOpts{
Name: "endlessh_client_closed_count_total",
Help: "Total number of clients that stopped connecting to this host.",
}, func() float64 {
return float64(numTotalClientsClosed)
},
)
totalBytes = prometheus.NewCounterFunc(
prometheus.CounterOpts{
Name: "endlessh_sent_bytes_total",
Help: "Total bytes sent to clients that tried to connect to this host.",
}, func() float64 {
return float64(numTotalBytes)
},
)
totalSeconds = prometheus.NewCounterFunc(
prometheus.CounterOpts{
Name: "endlessh_trapped_time_seconds_total",
Help: "Total seconds clients spent on endlessh.",
}, func() float64 {
return float64(numTotalMilliseconds) / 1000
},
)
clientIP = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "endlessh_client_open_count",
Help: "Number of connections of clients.",
},
[]string{"ip", "geohash", "country", "location"},
)
clientSeconds = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "endlessh_client_trapped_time_seconds",
Help: "Seconds a client spends on endlessh.",
},
[]string{"ip"},
)
promReg := prometheus.NewRegistry()
promReg.MustRegister(totalClients)
promReg.MustRegister(totalClientsClosed)
promReg.MustRegister(totalBytes)
promReg.MustRegister(totalSeconds)
promReg.MustRegister(clientIP)
promReg.MustRegister(clientSeconds)
handler := promhttp.HandlerFor(promReg, promhttp.HandlerOpts{EnableOpenMetrics: true})
http.Handle("/"+prometheusEntry, handler)
func startSending(maxClients int64, bannerMaxLength int64, records chan<- metrics.RecordEntry) chan *client.Client {
clients := make(chan *client.Client, maxClients)
go func() {
glog.Infof("Starting Prometheus on %v:%v, entry point is /%v", prometheusHost, prometheusPort, prometheusEntry)
http.ListenAndServe(prometheusHost+":"+prometheusPort, nil)
for {
c, more := <-clients
if !more {
return
}
go func() {
bytesSent, err := c.Send(bannerMaxLength)
remoteIpAddr := c.RemoteIpAddr()
localPort := c.LocalPort()
millisecondsSpent := c.MillisecondsSinceLast()
if err != nil {
c.Close()
records <- metrics.RecordEntry{
RecordType: metrics.RecordEntryTypeStop,
IpAddr: remoteIpAddr,
LocalPort: localPort,
MillisecondsSpent: millisecondsSpent,
}
return
}
clients <- c
records <- metrics.RecordEntry{
RecordType: metrics.RecordEntryTypeSend,
IpAddr: remoteIpAddr,
LocalPort: localPort,
MillisecondsSpent: millisecondsSpent,
BytesSent: bytesSent,
}
}()
}
}()
return clients
}
func startAccepting(maxClients int64, connType, connHost, connPort string, interval time.Duration, clients chan<- *client.Client, records chan<- metrics.RecordEntry, proxyProtocolEnabled bool, proxyProtocolReadHeaderTimeout int) {
go func() {
connPortInt, err := strconv.Atoi(connPort)
if err != nil {
glog.Errorf("Invalid port: %v", err)
os.Exit(1)
}
addr := connHost + fmt.Sprintf(":%d", connPortInt)
l, err := net.Listen(connType, addr)
if err != nil {
glog.Errorf("Error listening: %v", err)
os.Exit(1)
}
// Wrap the listener in a proxy protocol listener
if proxyProtocolEnabled {
l = &proxyproto.Listener{Listener: l, ReadHeaderTimeout: time.Duration(proxyProtocolReadHeaderTimeout) * time.Millisecond}
}
// Close the listener when the application closes.
defer l.Close()
realAddr := l.Addr().(*net.TCPAddr)
localPortStr := strconv.Itoa(realAddr.Port)
glog.Infof("Listening on %v:%v", connHost, realAddr.Port)
for {
// Listen for an incoming connection.
conn, err := l.Accept()
if err != nil {
glog.Errorf("Error accepting connection from port %v: %v", connPort, err)
os.Exit(1)
}
c := client.NewClient(conn, interval, maxClients)
remoteIpAddr := c.RemoteIpAddr()
records <- metrics.RecordEntry{
RecordType: metrics.RecordEntryTypeStart,
IpAddr: remoteIpAddr,
LocalPort: localPortStr,
}
clients <- c
}
}()
}
type arrayStrings []string
func (a *arrayStrings) String() string {
return strings.Join(*a, ", ")
}
func (a *arrayStrings) Set(value string) error {
*a = append(*a, value)
return nil
}
const defaultPort = "2222"
var connPorts arrayStrings
func main() {
intervalMs := flag.Int("interval_ms", 1000, "Message millisecond delay")
bannerMaxLength := flag.Int64("line_length", 32, "Maximum banner line length")
maxClients := flag.Int64("max_clients", 4096, "Maximum number of clients")
connType := flag.String("conn_type", "tcp", "Connection type. Possible values are tcp, tcp4, tcp6")
connHost := flag.String("host", "0.0.0.0", "SSH listening address")
connPort := flag.String("port", "2222", "SSH listening port")
flag.Var(&connPorts, "port", fmt.Sprintf("SSH listening port. You may provide multiple -port flags to listen to multiple ports. (default %q)", defaultPort))
prometheusEnabled := flag.Bool("enable_prometheus", false, "Enable prometheus")
prometheusHost := flag.String("prometheus_host", "0.0.0.0", "The address for prometheus")
prometheusPort := flag.String("prometheus_port", "2112", "The port for prometheus")
prometheusEntry := flag.String("prometheus_entry", "metrics", "Entry point for prometheus")
prometheusCleanUnseenSeconds := flag.Int("prometheus_clean_unseen_seconds", 0, "Remove series if the IP is not seen for the given time. Set to 0 to disable. (default 0)")
geoipSupplier := flag.String("geoip_supplier", "off", "Supplier to obtain Geohash of IPs. Possible values are \"off\", \"ip-api\", \"max-mind-db\"")
maxMindDbFileName = flag.String("max_mind_db", "", "Path to the MaxMind DB file.")
maxMindDbFileName := flag.String("max_mind_db", "", "Path to the MaxMind DB file.")
proxyProtocolEnabled := flag.Bool("proxy_protocol_enabled", false, "Enable PROXY protocol support. This causes the server to expect PROXY protocol headers on incoming connections.")
proxyProtocolReadHeaderTimeout := flag.Int("proxy_protocol_read_header_timeout_ms", 200, "Timeout for reading the PROXY protocol header in milliseconds. If the connection does not send a valid PROXY protocol header in this time, the header is ignored.")
flag.Usage = func() {
fmt.Fprintf(flag.CommandLine.Output(), "Usage of %v \n", os.Args[0])
@@ -126,60 +152,48 @@ func main() {
}
flag.Parse()
if *connType == "tcp6" && *prometheusHost == "0.0.0.0" {
*prometheusHost = "[::]"
}
if *prometheusEnabled {
initPrometheus(*prometheusHost, *prometheusPort, *prometheusEntry)
if *connType == "tcp6" && *prometheusHost == "0.0.0.0" {
*prometheusHost = "[::]"
}
if *prometheusPort == "0" || *prometheusPort == "" {
l, err := net.Listen("tcp", *prometheusHost+":0")
if err != nil {
glog.Fatalf("Failed to pick a free Prometheus port: %v", err)
}
actualPort := l.Addr().(*net.TCPAddr).Port
*prometheusPort = strconv.Itoa(actualPort)
l.Close()
}
metrics.InitPrometheus(*prometheusHost, *prometheusPort, *prometheusEntry)
}
rand.Seed(time.Now().UnixNano())
records := metrics.StartRecording(*maxClients, *prometheusEnabled, *prometheusCleanUnseenSeconds,
geoip.GeoOption{
GeoipSupplier: *geoipSupplier,
MaxMindDbFileName: *maxMindDbFileName,
})
clients := startSending(*maxClients, *bannerMaxLength, records)
interval := time.Duration(*intervalMs) * time.Millisecond
// Listen for incoming connections.
if *connType == "tcp6" && *connHost == "0.0.0.0" {
*connHost = "[::]"
}
l, err := net.Listen(*connType, *connHost+":"+*connPort)
if err != nil {
glog.Errorf("Error listening: %v", err)
os.Exit(1)
if len(connPorts) == 0 {
connPorts = append(connPorts, defaultPort)
}
// Close the listener when the application closes.
defer l.Close()
glog.Infof("Listening on %v:%v", *connHost, *connPort)
clients := make(chan *client, *maxClients)
go func() {
for {
c, more := <-clients
if !more {
return
for _, connPort := range connPorts {
startAccepting(*maxClients, *connType, *connHost, connPort, interval, clients, records, *proxyProtocolEnabled, *proxyProtocolReadHeaderTimeout)
}
for {
if *prometheusCleanUnseenSeconds <= 0 {
time.Sleep(time.Duration(1<<63 - 1))
} else {
time.Sleep(time.Second * time.Duration(60))
records <- metrics.RecordEntry{
RecordType: metrics.RecordEntryTypeClean,
}
if time.Now().Before(c.next) {
time.Sleep(c.next.Sub(time.Now()))
}
err := c.Send(*bannerMaxLength)
if err != nil {
c.Close()
continue
}
go func() { clients <- c }()
}
}()
listener := func() {
for {
// Listen for an incoming connection.
conn, err := l.Accept()
if err != nil {
glog.Errorf("Error accepting: %v", err)
os.Exit(1)
}
// Handle connections in a new goroutine.
for numCurrentClients >= *maxClients {
time.Sleep(interval)
}
clients <- NewClient(conn, interval, *maxClients, *geoipSupplier, *prometheusEnabled)
}
}
listener()
}
+195
View File
@@ -0,0 +1,195 @@
// Copyright (C) 2024-2026 Shizun Ge
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
package metrics
import (
"endlessh-go/geoip"
"net/http"
"os"
"time"
"strings"
"net"
"github.com/golang/glog"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
pq *UpdatablePriorityQueue
totalClients *prometheus.CounterVec
totalClientsClosed *prometheus.CounterVec
totalBytes *prometheus.CounterVec
totalSeconds *prometheus.CounterVec
clientIP *prometheus.CounterVec
clientSeconds *prometheus.CounterVec
)
func InitPrometheus(prometheusHost, prometheusPort, prometheusEntry string) {
pq = NewUpdatablePriorityQueue()
totalClients = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "endlessh_client_open_count_total",
Help: "Total number of clients that tried to connect to this host.",
}, []string{"local_port"},
)
totalClientsClosed = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "endlessh_client_closed_count_total",
Help: "Total number of clients that stopped connecting to this host.",
}, []string{"local_port"},
)
totalBytes = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "endlessh_sent_bytes_total",
Help: "Total bytes sent to clients that tried to connect to this host.",
}, []string{"local_port"},
)
totalSeconds = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "endlessh_trapped_time_seconds_total",
Help: "Total seconds clients spent on endlessh.",
}, []string{"local_port"},
)
clientIP = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "endlessh_client_open_count",
Help: "Number of connections of clients.",
},
[]string{"ip", "local_port", "geohash", "country", "location"},
)
clientSeconds = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "endlessh_client_trapped_time_seconds",
Help: "Seconds a client spends on endlessh.",
},
[]string{"ip", "local_port"},
)
promReg := prometheus.NewRegistry()
promReg.MustRegister(totalClients)
promReg.MustRegister(totalClientsClosed)
promReg.MustRegister(totalBytes)
promReg.MustRegister(totalSeconds)
promReg.MustRegister(clientIP)
promReg.MustRegister(clientSeconds)
handler := promhttp.HandlerFor(promReg, promhttp.HandlerOpts{EnableOpenMetrics: true})
http.Handle("/"+prometheusEntry, handler)
go func() {
if strings.HasPrefix(prometheusHost, "unix:") {
socketPath := prometheusHost[5:] // trim the "unix:" prefix
glog.Infof("Starting Prometheus on Unix socket %v, entry point is /%v", socketPath, prometheusEntry)
serveOnUnixSocket(socketPath)
} else {
ipPort := prometheusHost+":"+prometheusPort
glog.Infof("Starting Prometheus on IP port %v, entry point is /%v", ipPort, prometheusEntry)
serveOnIpPort(ipPort)
}
}()
}
func serveOnUnixSocket(socketPath string) {
_ = os.Remove(socketPath) // allow failure
unixListener, err := net.Listen("unix", socketPath)
if err != nil {
glog.Errorf("Error starting Prometheus on socket %v: %v", socketPath, err)
os.Exit(1)
}
if err := http.Serve(unixListener, nil); err != nil {
glog.Errorf("Error starting Prometheus at socket %v: %v", socketPath, err)
os.Exit(1)
}
}
func serveOnIpPort(ipPort string) {
if err := http.ListenAndServe(ipPort, nil); err != nil {
glog.Errorf("Error starting Prometheus at IP port %v: %v", ipPort, err)
os.Exit(1)
}
}
const (
RecordEntryTypeStart = iota
RecordEntryTypeSend = iota
RecordEntryTypeStop = iota
RecordEntryTypeClean = iota
)
type RecordEntry struct {
RecordType int
IpAddr string
LocalPort string
MillisecondsSpent int64
BytesSent int
}
func StartRecording(maxClients int64, prometheusEnabled bool, prometheusCleanUnseenSeconds int, geoOption geoip.GeoOption) chan RecordEntry {
records := make(chan RecordEntry, maxClients)
go func() {
for {
r, more := <-records
if !more {
return
}
if !prometheusEnabled {
continue
}
switch r.RecordType {
case RecordEntryTypeStart:
geohash, country, location, err := geoip.GeohashAndLocation(r.IpAddr, geoOption)
if err != nil {
glog.Warningf("Failed to obtain the geohash of %v: %v.", r.IpAddr, err)
}
clientIP.With(prometheus.Labels{
"ip": r.IpAddr,
"local_port": r.LocalPort,
"geohash": geohash,
"country": country,
"location": location}).Inc()
totalClients.With(prometheus.Labels{"local_port": r.LocalPort}).Inc()
pq.Update(r.IpAddr, time.Now())
case RecordEntryTypeSend:
secondsSpent := float64(r.MillisecondsSpent) / 1000
clientSeconds.With(prometheus.Labels{
"ip": r.IpAddr,
"local_port": r.LocalPort}).Add(secondsSpent)
totalSeconds.With(prometheus.Labels{"local_port": r.LocalPort}).Add(secondsSpent)
totalBytes.With(prometheus.Labels{"local_port": r.LocalPort}).Add(float64(r.BytesSent))
pq.Update(r.IpAddr, time.Now())
case RecordEntryTypeStop:
secondsSpent := float64(r.MillisecondsSpent) / 1000
clientSeconds.With(prometheus.Labels{
"ip": r.IpAddr,
"local_port": r.LocalPort}).Add(secondsSpent)
totalSeconds.With(prometheus.Labels{"local_port": r.LocalPort}).Add(secondsSpent)
totalClientsClosed.With(prometheus.Labels{"local_port": r.LocalPort}).Inc()
pq.Update(r.IpAddr, time.Now())
case RecordEntryTypeClean:
top := pq.Peek()
deadline := time.Now().Add(-time.Second * time.Duration(prometheusCleanUnseenSeconds))
for top != nil && top.Value.Before(deadline) {
clientIP.DeletePartialMatch(prometheus.Labels{"ip": top.Key})
clientSeconds.DeletePartialMatch(prometheus.Labels{"ip": top.Key})
pq.Pop()
top = pq.Peek()
}
}
}
}()
return records
}
+94
View File
@@ -0,0 +1,94 @@
package metrics
import (
"container/heap"
"time"
)
// Pair represents a key-value pair with a timestamp
type Pair struct {
Key string
Value time.Time
HeapIdx int // Index in the heap for efficient updates
}
// PriorityQueue is a min-heap implementation for Pairs
type PriorityQueue []*Pair
// Len returns the length of the priority queue
func (pq PriorityQueue) Len() int { return len(pq) }
// Less compares two pairs based on their values (timestamps)
func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].Value.Before(pq[j].Value)
}
// Swap swaps two pairs in the priority queue
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].HeapIdx = i
pq[j].HeapIdx = j
}
// Push adds a pair to the priority queue
func (pq *PriorityQueue) Push(x interface{}) {
pair := x.(*Pair)
pair.HeapIdx = len(*pq)
*pq = append(*pq, pair)
}
// Pop removes the pair with the minimum value (timestamp) from the priority queue
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
pair := old[n-1]
pair.HeapIdx = -1 // for safety
*pq = old[0 : n-1]
return pair
}
// UpdatablePriorityQueue represents the data structure with the priority queue
type UpdatablePriorityQueue struct {
pq PriorityQueue
keyMap map[string]*Pair
}
// NewUpdatablePriorityQueue initializes a new UpdatablePriorityQueue
func NewUpdatablePriorityQueue() *UpdatablePriorityQueue {
return &UpdatablePriorityQueue{
pq: make(PriorityQueue, 0),
keyMap: make(map[string]*Pair),
}
}
// Update adds or updates a key-value pair in the data structure
func (ds *UpdatablePriorityQueue) Update(key string, value time.Time) {
if pair, ok := ds.keyMap[key]; ok {
// Key exists, update the time
pair.Value = value
heap.Fix(&ds.pq, pair.HeapIdx)
} else {
// Key does not exist, create a new entry
pair := &Pair{Key: key, Value: value}
heap.Push(&ds.pq, pair)
ds.keyMap[key] = pair
}
}
// Peek returns the entry with the minimal time
func (ds *UpdatablePriorityQueue) Peek() *Pair {
if ds.pq.Len() == 0 {
return nil
}
return ds.pq[0]
}
// Pop removes the entry with the minimal time
func (ds *UpdatablePriorityQueue) Pop() *Pair {
if ds.pq.Len() == 0 {
return nil
}
pair := heap.Pop(&ds.pq).(*Pair)
delete(ds.keyMap, pair.Key)
return pair
}