1
mirror of https://github.com/xddxdd/bird-lg-go synced 2025-10-17 22:42:12 +02:00

138 Commits

Author SHA1 Message Date
Lan Tian
abb32abff3 general: add unit test for docker images 2023-09-08 18:45:58 -07:00
Lan Tian
b368c75aa3 frontend: fix whois client cannot get default whois port 2023-09-08 18:38:23 -07:00
Lan Tian
09405cdb38 frontend: also print whois client output on error 2023-09-08 18:22:31 -07:00
Lan Tian
f999d47d9f frontend: force enable whois client regex parser on alpine/musl 2023-09-07 19:14:04 -07:00
Lan Tian
005dfb1435 frontend: make docker image whois client try to use config file 2023-09-07 00:51:56 -07:00
Lan Tian
4bd7a6bb95 general: also release docker image to GitHub container registry 2023-09-06 21:06:10 -07:00
Lan Tian
462d76a2d0 general: reenable docker multiarch build 2023-09-06 21:02:32 -07:00
Lan Tian
58f217578c readme: add note about development version of docker image 2023-09-06 20:59:27 -07:00
Lan Tian
0e95727de1 general: reorganize GitHub Actions workflows and readd unit test 2023-09-06 20:55:45 -07:00
Lan Tian
a48f1c8040 general: move Docker image build to GitHub Actions 2023-09-06 20:48:14 -07:00
Lan Tian
81acde3a37 frontend: add whois client for more complex whois lookup 2023-09-06 20:35:30 -07:00
Lan Tian
7c0fe0d512 proxy: update traceroute version in Docker image 2023-09-06 20:33:40 -07:00
dependabot[bot]
a5f4452d02 build(deps): bump github.com/jarcoal/httpmock in /frontend (#82)
Bumps [github.com/jarcoal/httpmock](https://github.com/jarcoal/httpmock) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/jarcoal/httpmock/releases)
- [Commits](https://github.com/jarcoal/httpmock/compare/v1.3.0...v1.3.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-25 00:44:30 -07:00
Lan Tian
b237185ef7 release: v1.3.1 2023-06-18 20:14:41 -07:00
towalink
e949646790 Properly escape URL path (#81) 2023-06-10 15:14:10 -07:00
dependabot[bot]
bb479d22ae build(deps): bump github.com/spf13/viper from 1.15.0 to 1.16.0 in /proxy (#79)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.15.0 to 1.16.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.15.0...v1.16.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-02 00:58:12 -07:00
dependabot[bot]
d40f41b4d5 build(deps): bump github.com/spf13/viper in /frontend (#80)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.15.0 to 1.16.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.15.0...v1.16.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-02 00:58:06 -07:00
Lan Tian
cdc34704b5 release: v1.3.0 2023-05-14 12:37:46 -07:00
Lan Tian
db58bd3354 frontend: add a test case for lookup DNS -> WHOIS fallback 2023-05-06 00:26:40 -07:00
Lan Tian
a0246ccee2 general: add unit tests for >80% coverage
Includes a few minor fixes:
- frontend: support setting port for WHOIS server
- proxy: fix handling of very long lines
- proxy: refactor IP allowlist logic, parse allow IP list at startup
2023-05-06 00:23:28 -07:00
James Lu
ccd14af0c8 settings: treat empty environment variables as set (#77)
This allows disabling specific options like dns_interface or whois via environment variables.

ref: https://github.com/spf13/viper#working-with-environment-variables
2023-05-05 21:36:38 -07:00
Lan Tian
594ca80f50 frontend: fix whois lookup & only show bgpmap nexthop info on the first hop 2023-05-05 20:20:12 -07:00
Lan Tian
5625058e71 frontend: use ASN as bgpmap node identifier (instead of resolved whois result) 2023-05-05 19:52:30 -07:00
Lan Tian
7efa3237a9 frontend: refactor bgpmap code to fix #75 2023-05-05 01:58:05 -07:00
Lan Tian
7b0c8c0556 general: bump go version in go.mod 2023-01-26 22:01:47 -08:00
dependabot[bot]
ffd9165062 build(deps): bump github.com/spf13/viper in /frontend (#73)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.14.0 to 1.15.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.14.0...v1.15.0)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-23 10:50:42 -08:00
dependabot[bot]
24fd5203e8 build(deps): bump github.com/spf13/viper from 1.14.0 to 1.15.0 in /proxy (#74)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.14.0 to 1.15.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.14.0...v1.15.0)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-23 10:50:30 -08:00
Lan Tian
49a05767c1 ci: bump version for go-release-action 2023-01-08 01:16:23 -06:00
Lan Tian
e7010f75f8 release: v1.2.0 2023-01-06 23:05:05 -06:00
Yuhui Xu
dba2af7634 proxy: fix description for --traceroute_flags (#70) 2022-12-27 15:38:41 -06:00
Yuhui Xu
049775319b proxy: autodetect traceroute args on startup (#69) 2022-12-25 15:41:29 -06:00
Lan Tian
47c66b125c release: v1.1.1 2022-12-18 16:26:47 -06:00
Yuhui Xu
9e17b116f1 frontend: refactor bgpmap and fix node colors (#67)
* frontend: refactor bgpmap and fix node colors

* frontend: alternative way to test bgpmap
2022-12-07 16:30:19 -06:00
Lan Tian
335ad40634 release: v1.1.0 2022-11-27 17:22:21 -06:00
dependabot[bot]
6ec0f2e7a6 build(deps): bump github.com/spf13/viper from 1.13.0 to 1.14.0 in /proxy (#65)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.13.0 to 1.14.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.13.0...v1.14.0)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-07 20:26:44 -06:00
dependabot[bot]
4b73cf0fcb build(deps): bump github.com/spf13/viper in /frontend (#64)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.13.0 to 1.14.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.13.0...v1.14.0)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-07 20:26:37 -06:00
Klara Modin
3b1d001543 frontend: sortable tables in summary (#61)
Adapted from https://stackoverflow.com/a/57080195.
Additions:
1. sortTable accepts a secondary column and sorting direction. The 'Name'
   column (number 0) is always used for the secondary
2. use classes 'ascSorted' and 'descSorted' to toggle between ascending and
   descending order
3. in the table functions, use .innerHTML instead of .innnerText so the
   link to detailed protocol information does not get lost. Also
   preserve .classList
2022-09-18 15:58:20 -05:00
dependabot[bot]
675cb26ed1 build(deps): bump github.com/spf13/viper from 1.12.0 to 1.13.0 in /proxy (#63)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.12.0...v1.13.0)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-14 12:22:03 -05:00
dependabot[bot]
556d3e50d3 build(deps): bump github.com/spf13/viper in /frontend (#62)
Bumps [github.com/spf13/viper](https://github.com/spf13/viper) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/spf13/viper/releases)
- [Commits](https://github.com/spf13/viper/compare/v1.12.0...v1.13.0)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-14 12:21:56 -05:00
Lan Tian
06796f546e general: remove failing docker image build tasks for PRs 2022-08-25 11:42:41 -05:00
Potat0
d029d6684c Fix the wrong order of examples (#60) 2022-08-17 11:44:35 -05:00
日下部 詩
5ce0f55f35 1. support local whois. 2 add some useful bird command (#59) 2022-08-11 22:34:39 -04:00
Lan Tian
890ab51b07 release: v1.0.0 2022-08-05 22:36:43 -04:00
Lan Tian
8e4a35cc8c general: fix GOARCH for ARM 32 bit 2022-08-05 22:33:33 -04:00
Lan Tian
97f3c6088f general: add GitHub actions for releasing binaries 2022-08-05 22:29:30 -04:00
Yuhui Xu
982326a678 frontend: fix XSS (#57) (#58) 2022-08-05 21:59:18 -04:00
Tristan Heaven
4b3980f6bd Fix navbar_brand_url config (#56) 2022-07-28 09:54:39 -04:00
Yuhui Xu
6f6b2bd283 general: support reading config files (#55) 2022-07-08 23:13:10 -04:00
Yuhui Xu
892a7bee22 frontend: support listening on unix socket (#54) 2022-07-08 21:14:11 -04:00
Nicolas Lorin
348295b9aa frontend: add the abilities to customized timeout time (#51)
* main.go: add timeout setting

* lgproxy.go: use timeout setting when querying server

* README.md: add new timeout setting
2022-02-08 02:29:05 -06:00
Kioubit
950c018b18 Confirm that bird access was restricted (#49)
Co-authored-by: Kioubit <kioubit@localhost.invalid>
2022-01-18 03:03:09 -06:00
herver
26efeb4996 Add name filter feature (#48)
This uses a RE2 regexp to hide protocols which name matches the expression
2022-01-18 03:01:57 -06:00
Lan Tian
5a5dfbc93f general: add docker hub links to readme 2022-01-09 01:51:36 -06:00
Lan Tian
f60a292129 general: build docker images with correct arch label 2022-01-09 01:45:00 -06:00
James Lu
e7f6026854 Add BIRDLG_TRACEROUTE_RAW option to leave traceroute output in the default format (#47) 2022-01-09 00:14:31 -06:00
Lan Tian
a4e0f4c193 frontend: skip network related tests when unavailable
Fix #46
2022-01-09 00:10:14 -06:00
日下部 詩
af5b653326 BIRDLG_BGPMAP_INFO 選項 (#44)
* BIRDLG_BGPMAP_INFO

update the paramater

description fix for bgpmap_test

singleline and multiline

* Static file instead of jsdelivr; favicon.ico

Co-authored-by: testscript <testscript@example.com>
2021-12-20 03:35:43 -06:00
日下部 詩
58847759b3 一些小改動 (#42)
* 1. remove ":" at the start of port assignement. 2. use BIRDLG_PROXY_PORT at proxy. 3. add custom URL to brand

* goto / if only one server

* add BIRDLG_TRACEROUTE_BIN
2021-11-09 12:27:02 -06:00
Yuhui Xu
6481e7cc8d frontend: fix uninitialized buffer (#41) 2021-09-26 13:26:07 -05:00
James Lu
2166d73b3d frontend: add filtering by protocol type to summary tables (#40)
* frontend: add option to filter by protocol type

Closes #33.

* frontend: use case insensitive comparisons for protocol filter
2021-09-07 15:17:16 -05:00
Yuhui Xu
a64d839e2c frontend: limit fetched response size to 64KB (#39) 2021-09-02 20:21:28 -05:00
James Lu
1a3c618522 frontend: BGPmap improvements (#36)
* bgpmap: Compact nexthop info into an edge label

* bgpmap: parse and show non-BGP routes

* bgpmap: Misc tweaks

- Show the protocol name instead of the ASN in edge labels
- Correctly draw only the primary path if there are multiple routes to the first neighbour ASN in a path
- Use a smaller font size for edge labels

* bgpmap_test: update to match new changes

* bgpmap: Split route info on all (non-empty) rta_dest_names values
2021-08-31 09:44:14 -05:00
Yuhui Xu
fbd190628c general: add go 1.16 requirement to readme [skip ci] (#37) 2021-08-30 23:46:14 -05:00
Yuhui Xu
823b639245 frontend: also filter whois privacy redacted lines (#34) 2021-08-28 22:02:03 -05:00
Yuhui Xu
b0c0e5442d frontend: set lgproxy request timeout to 120s (#31)
lgproxy traceroutecan be really slow if dns resolve doesnt work well.
2021-08-04 00:30:38 +08:00
Yuhui Xu
4e4ce89418 frontend: set timeout longer for lgproxy requests (#30) 2021-08-03 11:46:05 +08:00
Yuhui Xu
234aadadd9 frontend: specify timeout for requests (#29) 2021-08-02 18:46:43 +08:00
Lan Tian
bee26f421c frontend: resolve asn in dns/whois/fail order & fix tests 2021-07-31 17:11:20 +08:00
Yuhui Xu
2e0cb131ca Merge pull request #27 from miegl/master
frontend: optional ASN resolution using whois
2021-07-31 17:02:25 +08:00
Josef Miegl
4c248c638a frontend: optional asn resolution using whois 2021-07-30 16:54:41 +02:00
Yuhui Xu
3550362a4d Merge pull request #26 from sesa-me/master
Refactor to use go:embed
2021-07-14 22:13:36 +08:00
Simon Marsh
256a80646f - Refactor file embedding to use Go 1.16 embed functionality.
- Remove references to previous bindata packages from build scripts and docs
2021-07-13 11:54:35 +01:00
Yuhui Xu
03c42eb1e8 Merge pull request #25 from outloudvi/patch-1
doc: add --net-specific-mode
2021-07-03 22:20:56 +08:00
Outvi V
aea85e774c doc: add --net-specific-mode 2021-07-03 12:33:49 +08:00
Yuhui Xu
80d9351a58 Merge pull request #24 from xddxdd/lantian-dev
frontend: allow long lines if result is short
2021-06-21 01:01:37 +08:00
Lan Tian
5e0bc081e6 frontend: allow long lines if result is short 2021-06-21 00:57:26 +08:00
Yuhui Xu
4d53d1f095 Merge pull request #23 from xddxdd/lantian-dev
frontend: change behavior of whois shorten mode
2021-06-21 00:49:37 +08:00
Lan Tian
5883015294 frontend: change behavior of whois shorten mode 2021-06-21 00:44:44 +08:00
Yuhui Xu
80e66a7a81 Merge pull request #22 from xddxdd/lantian-dev
frontend: add generic whois shorten mode
2021-06-20 02:24:49 +08:00
Lan Tian
41329da7cb frontend: add generic whois shorten mode 2021-06-20 02:20:18 +08:00
Yuhui Xu
8e56705205 Merge pull request #21 from xddxdd/lantian-dev
frontend: fix typo
2021-06-19 16:42:01 +08:00
Lan Tian
6a8b3a0e55 frontend: fix typo 2021-06-19 16:36:18 +08:00
Yuhui Xu
83ab403706 Merge pull request #20 from xddxdd/lantian-dev
frontend: limit telegram commands by bot name
2021-06-19 16:27:17 +08:00
Lan Tian
7c7814cc7b frontend: limit telegram commands by bot name 2021-06-19 16:23:43 +08:00
Yuhui Xu
8598060cc0 Merge pull request #19 from xddxdd/lantian-dev
Add instruction for create Dockerfile
2021-05-21 21:11:00 +08:00
Lan Tian
bda06ddd5e Add instruction for create Dockerfile 2021-05-21 21:09:50 +08:00
Yuhui Xu
f404072ab8 Merge pull request #18 from xddxdd/dependabot/add-v2-config-file
Upgrade to GitHub-native Dependabot
2021-05-01 23:21:14 +08:00
dependabot-preview[bot]
fa827502cf Upgrade to GitHub-native Dependabot 2021-04-29 22:35:16 +00:00
Yuhui Xu
794125a96f Merge pull request #17 from towalink/master
Allow specifying display names for servers
2021-04-18 19:37:22 +08:00
Henri
de9d9101b1 Fix test initialization so that tests succeed after previous commit 2021-04-14 09:17:44 +02:00
Henri
056ef3769e Allow specifying display names for servers 2021-04-13 21:58:50 +02:00
towalink
974e809deb Merge pull request #1 from xddxdd/master
Merge pull request #15 from towalink/master
2021-04-10 08:36:39 +02:00
Yuhui Xu
6e19b5ae64 Merge pull request #15 from towalink/master
Increase consistency of path escaping;  support IPv6 addresses
2021-04-10 10:25:45 +08:00
Henri
874089117b Increase consistency of path escaping and support IPv6 addresses instead of hostnames 2021-04-06 21:43:58 +02:00
Yuhui Xu
f77a8a28fe Merge pull request #14 from xddxdd/lantian-dev
Fix link in README
2021-04-01 22:57:56 +08:00
Lan Tian
9e8a845658 general: fix link in README 2021-04-01 22:56:13 +08:00
Yuhui Xu
fd3e7b8379 Merge pull request #13 from xddxdd/lantian-dev
Add build notes from #11
2021-04-01 22:54:41 +08:00
Lan Tian
8765189deb general: add build notes from #11 2021-04-01 22:47:08 +08:00
Yuhui Xu
492942cce1 Merge pull request #12 from AluisioASG/domainless
frontend: make domain optional
2021-04-01 22:43:13 +08:00
Aluísio Augusto Silva Gonçalves
f81a5308ae frontend: make domain optional
Making the domain optional allows usage of bare hostnames for
the servers (e.g. when they're statically configured) and even
IP addresses if someone is so inclined (although presentation
might suffer in this case).
2021-03-31 16:44:44 -03:00
Lan Tian
5b5a09ccbd frontend: clamp telegram api response to 4096 chars 2021-03-31 22:43:46 +08:00
Lan Tian
dc4d7e6532 general: update makefiles for project 2021-03-15 00:49:13 +08:00
Lan Tian
28a7d2a53f general: fix incorrect name for pushed docker images 2021-03-06 21:41:44 +08:00
Lan Tian
4413f1032f general: try to fix multiarch build 2021-03-06 21:21:42 +08:00
Lan Tian
007b66e036 Revert "general: remove build for all arch but amd64"
This reverts commit 1c3d9ec594.
2021-03-06 20:52:04 +08:00
Lan Tian
3f612d2e76 proxy: fix plain traceroute not executed 2021-02-28 23:09:11 +08:00
Lan Tian
f49f8bac5e proxy: support arbitraty traceroute arguments 2021-02-27 16:42:42 +08:00
Lan Tian
f6ddc5761b frontend: remove unnecessary URL escapes 2021-02-27 15:24:21 +08:00
Lan Tian
1c3d9ec594 general: remove build for all arch but amd64 2021-01-18 23:13:25 +08:00
Lan Tian
6cc0c617b4 frontend: add API for server list 2021-01-17 16:16:41 +08:00
Lan Tian
e2cc580da3 frontend: add CORS header to API 2021-01-17 12:45:20 +08:00
Lan Tian
472cec74b0 general: update README.md 2021-01-17 12:37:22 +08:00
Lan Tian
da2c3d9aed frontend: add API 2021-01-17 12:35:29 +08:00
Lan Tian
aa76bc3de7 ci: try fix test error 2021-01-17 02:39:17 +08:00
Lan Tian
a984095282 frontend: add tests against XSS 2021-01-17 02:21:23 +08:00
Lan Tian
1baf325149 frontend: move redirect logic to HTML 2021-01-17 01:33:14 +08:00
Lan Tian
72946e1113 frontend: filter output to prevent XSS 2021-01-17 01:14:49 +08:00
Lan Tian
90e5012840 proxy: filter input to prevent XSS 2021-01-15 01:22:39 +08:00
Lan Tian
8d5eb56199 Fix building Docker image for arm and i386 2021-01-15 01:00:54 +08:00
Lan Tian
8d0618fed9 Update CircleCI config 2021-01-15 00:41:38 +08:00
Yuhui Xu
f8ea511d44 Merge pull request #8 from sesa-me/burble.dn42-templates
Add static file bundling and HTML templating
2021-01-14 23:01:43 +08:00
Yuhui Xu
b99eb60c30 Merge pull request #9 from xddxdd/circleci-project-setup
Circleci project setup
2021-01-14 00:02:18 +08:00
Yuhui Xu
9f934ca53c Updated config.yml 2021-01-13 23:58:44 +08:00
Yuhui Xu
ee7cc1675b Add .circleci/config.yml 2021-01-13 23:37:32 +08:00
Simon Marsh
f4b6955343 Add utility functions for filtering results and rename templates 2021-01-12 10:21:03 +00:00
Simon Marsh
78ce724171 Fix bindata build step and parameterize docker build 2021-01-12 10:21:02 +00:00
Simon Marsh
6179c688be - Use bindata to package static file content in to the frontend binary
- Add golang templates to move HTML rendering out of the go code where possible
- Add an endpoint for serving static files
- Add URL escaping for servers and targets
2021-01-11 15:00:05 +00:00
Lan Tian
8d0e210572 Fix #7 2021-01-11 22:24:15 +08:00
Lan Tian
26c51176e4 proxy: add back ipv6 endpoints for compatibility with original project 2020-11-20 21:58:44 +08:00
Yuhui Xu
5cf2ac57b8 Merge pull request #6 from petabyteboy/master
preserve leading spaces
2020-11-19 23:22:00 +08:00
Milan Pässler
75bc63ffa7 preserve leading spaces 2020-11-18 19:27:46 +01:00
Lan Tian
438c6a1f82 general: fix travis multiarch 2020-11-09 01:37:09 +08:00
Lan Tian
b98d783739 general: use stable debian to build docker image 2020-11-09 01:23:58 +08:00
Lan Tian
5000ad1bbf general: add s390x & ppc64le 2020-11-07 20:24:37 +08:00
Lan Tian
538699ccd2 proxy: scratch-based docker image 2020-11-07 20:20:42 +08:00
Lan Tian
9e77de6b46 frontend: scratch-based docker image 2020-11-07 20:06:07 +08:00
Lan Tian
c15942cc32 proxy: fix regex formatting error 2020-10-30 23:33:56 +08:00
Lan Tian
3bcfc3d36c Remove BIRDv1 support 2020-10-30 23:10:03 +08:00
73 changed files with 8141 additions and 876 deletions

16
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
version: 2
updates:
- package-ecosystem: gomod
directory: "/frontend"
schedule:
interval: daily
time: "08:00"
timezone: Asia/Shanghai
open-pull-requests-limit: 10
- package-ecosystem: gomod
directory: "/proxy"
schedule:
interval: daily
time: "08:00"
timezone: Asia/Shanghai
open-pull-requests-limit: 10

108
.github/workflows/develop.yaml vendored Normal file
View File

@@ -0,0 +1,108 @@
on:
push:
branches:
- '**'
pull_request:
branches:
- 'master'
jobs:
go-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Golang
uses: actions/setup-go@v4
- name: Run frontend unit test
run: |
export GO111MODULE=on
cd frontend
go get -v -t -d ./...
go test -v ./...
cd ..
- name: Run proxy unit test
run: |
export GO111MODULE=on
cd proxy
go get -v -t -d ./...
go test -v ./...
cd ..
docker-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Test whois binary in frontend image
run: |
docker build -t local/frontend frontend/
docker run --rm --net host --entrypoint whois local/frontend github.com || exit 1
docker run --rm --net host --entrypoint whois local/frontend -h whois.ripe.net github.com || exit 1
docker run --rm --net host --entrypoint whois local/frontend -h whois.ripe.net:43 github.com || exit 1
- name: Test traceroute binary in proxy image
run: |
docker build -t local/proxy proxy/
docker run --rm --net host --entrypoint traceroute local/proxy 127.0.0.1 || exit 1
docker run --rm --net host --entrypoint traceroute local/proxy ::1 || exit 1
docker-develop:
runs-on: ubuntu-latest
needs:
- go-test
- docker-test
if: github.event_name != 'pull_request'
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build frontend docker image
uses: docker/build-push-action@v4
with:
context: '{{defaultContext}}:frontend'
platforms: linux/amd64,linux/arm64,linux/386,linux/arm/v7
push: true
tags: |
xddxdd/bird-lg-go:develop
xddxdd/bird-lg-go:develop-${{ github.sha }}
ghcr.io/xddxdd/bird-lg-go:frontend-develop
ghcr.io/xddxdd/bird-lg-go:frontend-develop-${{ github.sha }}
- name: Build proxy docker image
uses: docker/build-push-action@v4
with:
context: '{{defaultContext}}:proxy'
platforms: linux/amd64,linux/arm64,linux/386,linux/arm/v7
push: true
tags: |
xddxdd/bird-lgproxy-go:develop
xddxdd/bird-lgproxy-go:develop-${{ github.sha }}
ghcr.io/xddxdd/bird-lg-go:proxy-develop
ghcr.io/xddxdd/bird-lg-go:proxy-develop-${{ github.sha }}

82
.github/workflows/release.yaml vendored Normal file
View File

@@ -0,0 +1,82 @@
on:
release:
types: [created]
jobs:
go-release:
name: Release Go Binary
runs-on: ubuntu-latest
strategy:
matrix:
goos: [linux, windows, darwin]
goarch: ["386", amd64, "arm", arm64]
exclude:
- goarch: "386"
goos: darwin
- goarch: "arm"
goos: darwin
- goarch: "arm"
goos: windows
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Release frontend
uses: wangyoucao577/go-release-action@v1.34
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
project_path: "./frontend"
binary_name: "bird-lg-go"
- name: Release proxy
uses: wangyoucao577/go-release-action@v1.34
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
project_path: "./proxy"
binary_name: "bird-lgproxy-go"
docker-release:
runs-on: ubuntu-latest
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build frontend docker image
uses: docker/build-push-action@v4
with:
context: '{{defaultContext}}:frontend'
platforms: linux/amd64,linux/arm64,linux/386,linux/arm/v7
push: true
tags: |
xddxdd/bird-lg-go:latest
ghcr.io/xddxdd/bird-lg-go:frontend
- name: Build proxy docker image
uses: docker/build-push-action@v4
with:
context: '{{defaultContext}}:proxy'
platforms: linux/amd64,linux/arm64,linux/386,linux/arm/v7
push: true
tags: |
xddxdd/bird-lgproxy-go:latest
ghcr.io/xddxdd/bird-lg-go:proxy

9
.gitignore vendored
View File

@@ -16,4 +16,11 @@
.DS_Store
frontend/frontend
proxy/proxy
proxy/proxy
# don't include generated bindata file
frontend/bindata.go
# don't include generated Dockerfiles
frontend/Dockerfile.*
proxy/Dockerfile.*

View File

@@ -1,35 +0,0 @@
language: minimal
os: linux
dist: focal
services:
- docker
env:
- PROGRAM=frontend IMAGE_NAME=bird-lg-go IMAGE_ARCH=i386
- PROGRAM=frontend IMAGE_NAME=bird-lg-go IMAGE_ARCH=amd64
- PROGRAM=frontend IMAGE_NAME=bird-lg-go IMAGE_ARCH=arm32v7
- PROGRAM=frontend IMAGE_NAME=bird-lg-go IMAGE_ARCH=arm64v8
- PROGRAM=proxy IMAGE_NAME=bird-lgproxy-go IMAGE_ARCH=i386
- PROGRAM=proxy IMAGE_NAME=bird-lgproxy-go IMAGE_ARCH=amd64
- PROGRAM=proxy IMAGE_NAME=bird-lgproxy-go IMAGE_ARCH=arm32v7
- PROGRAM=proxy IMAGE_NAME=bird-lgproxy-go IMAGE_ARCH=arm64v8
install:
- docker run --rm --privileged multiarch/qemu-user-static:register --reset
- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
script:
- |
# Build image
docker build \
-t $DOCKER_USERNAME/$IMAGE_NAME:$IMAGE_ARCH \
-f $PROGRAM/Dockerfile.$IMAGE_ARCH \
$PROGRAM
# Tag image :{arch} and :{arch}-build{build number}
docker tag $DOCKER_USERNAME/$IMAGE_NAME:$IMAGE_ARCH $DOCKER_USERNAME/$IMAGE_NAME:$IMAGE_ARCH-build$TRAVIS_BUILD_NUMBER
if [ "$IMAGE_ARCH" = "amd64" ]; then
# Tag as latest for amd64 images
docker tag $DOCKER_USERNAME/$IMAGE_NAME:$IMAGE_ARCH $DOCKER_USERNAME/$IMAGE_NAME:latest
docker tag $DOCKER_USERNAME/$IMAGE_NAME:$IMAGE_ARCH $DOCKER_USERNAME/$IMAGE_NAME:build$TRAVIS_BUILD_NUMBER
fi
- docker push $DOCKER_USERNAME/$IMAGE_NAME

13
Makefile Normal file
View File

@@ -0,0 +1,13 @@
frontend:
$(MAKE) -C frontend all
proxy:
$(MAKE) -C proxy all
.DEFAULT_GOAL := all
.PHONY: all frontend proxy
all: frontend proxy
install:
install -m 755 frontend/frontend /usr/local/bin/bird-lg-go
install -m 755 proxy/proxy /usr/local/bin/bird-lgproxy-go

221
README.md

File diff suppressed because it is too large Load Diff

1
RELEASE Normal file
View File

@@ -0,0 +1 @@
v1.3.1

202
docs/API.md Normal file
View File

@@ -0,0 +1,202 @@
# Bird-lg-go API documentation
The frontend provides an API for running BIRD/traceroute/whois queries.
API Endpoint: `https://your.frontend.com/api/` (the last slash must not be omitted!)
Requests are sent as POSTS with JSON bodies.
## Table of Contents
* [Bird-lg-go API documentation](#bird-lg-go-api-documentation)
* [Table of Contents](#table-of-contents)
* [Request fields](#request-fields)
* [Example request of type bird](#example-request-of-type-bird)
* [Example request of type server_list](#example-request-of-type-server_list)
* [Response fields (when type is summary)](#response-fields-when-type-is-summary)
* [Fields for apiSummaryResultPair](#fields-for-apisummaryresultpair)
* [Fields for SummaryRowData](#fields-for-summaryrowdata)
* [Example response](#example-response)
* [Response fields (when type is bird, traceroute, whois or server_list)](#response-fields-when-type-is-bird-traceroute-whois-or-server_list)
* [Fields for apiGenericResultPair](#fields-for-apigenericresultpair)
* [Example response of type bird](#example-response-of-type-bird)
* [Example response of type server_list](#example-response-of-type-server_list)
Created by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc)
## Request fields
| Name | Type | Value |
| ---- | ---- | -------- |
| `servers` | array of `string` | List of servers to be queried |
| `type` | `string` | Can be `summary`, `bird`, `traceroute`, `whois` or `server_list` |
| `args` | `string` | Arguments to be passed, see below |
Argument examples for each type:
- `summary`: `args` is ignored. Recommended to set to empty string.
- `bird`: `args` is the command to be passed to bird, e.g. `show route for 8.8.8.8`
- `traceroute`: `args` is the traceroute target, e.g. `8.8.8.8` or `google.com`
- `whois`: `args` is the whois target, e.g. `8.8.8.8` or `google.com`
- `server_list`: `args` is ignored. In addition, `servers` is also ignored.
### Example request of type `bird`
```json
{
"servers": [
"alpha"
],
"type": "bird",
"args": "show route for 8.8.8.8"
}
```
### Example request of type `server_list`
```json
{
"servers": [],
"type": "server_list",
"args": ""
}
```
## Response fields (when `type` is `summary`)
| Name | Type | Value |
| ---- | ---- | -------- |
| `error` | `string` | Error message when something is wrong. Empty when everything is good |
| `result` | array of `apiSummaryResultPair` | See below |
### Fields for `apiSummaryResultPair`
| Name | Type | Value |
| ---- | ---- | -------- |
| `server` | `string` | Name of the server |
| `data` | array of `SummaryRowData` | Summaries of the server, see below |
### Fields for `SummaryRowData`
All fields below is 1:1 correspondent to the output of `birdc show protocols`.
| Name | Type |
| ---- | ---- |
| `name` | `string` |
| `proto` | `string` |
| `table` | `string` |
| `state` | `string` |
| `since` | `string` |
| `info` | `string` |
### Example response
Request:
```json
{
"servers": [
"alpha"
],
"type": "summary",
"args": ""
}
```
Response:
```json
{
"error": "",
"result": [
{
"server": "alpha",
"data": [
{
"name": "bgp1",
"proto": "BGP",
"table": "---",
"state": "start",
"since": "2021-01-15 22:40:01",
"info": "Active Socket: Operation timed out"
},
{
"name": "bgp2",
"proto": "BGP",
"table": "---",
"state": "start",
"since": "2021-01-03 08:15:48",
"info": "Established"
}
]
}
]
}
```
## Response fields (when `type` is `bird`, `traceroute`, `whois` or `server_list`)
| Name | Type | Value |
| ---- | ---- | -------- |
| `error` | `string` | Error message, empty when everything is good |
| `result` | array of `apiGenericResultPair` | See below |
### Fields for `apiGenericResultPair`
| Name | Type | Value |
| ---- | ---- | -------- |
| `server` | `string` | Name of the server; is empty when type is `whois` |
| `data` | `string` | Result from the server; is empty when type is `server_list` |
### Example response of type `bird`
Request:
```json
{
"servers": [
"alpha"
],
"type": "bird",
"args": "show status"
}
```
Response:
```json
{
"error": "",
"result": [
{
"server": "alpha",
"data": "BIRD v2.0.7-137-g61dae32b\nRouter ID is 1.2.3.4\nCurrent server time is 2021-01-17 04:21:14.792\nLast reboot on 2021-01-03 08:15:48.494\nLast reconfiguration on 2021-01-17 00:49:10.573\nDaemon is up and running\n"
}
]
}
```
### Example response of type `server_list`
Request:
```json
{
"servers": [],
"type": "server_list",
"args": ""
}
```
Response:
```json
{
"error": "",
"result": [
{
"server": "gigsgigscloud",
"data": ""
}
]
}
```

22
docs/Telegram.md Normal file
View File

@@ -0,0 +1,22 @@
# Telegram Bot Webhook
The frontend can act as a Telegram Bot webhook endpoint, to add BGP route/traceroute/whois lookup functionality to your tech group.
There is no configuration necessary on the frontend, just start it up normally.
Set your Telegram Bot webhook URL to `https://your.frontend.com/telegram/alpha+beta+gamma`, where `alpha+beta+gamma` is the list of servers to be queried on Telegram commands, separated by `+`.
You may omit `alpha+beta+gamma` to use all your servers, but it is not recommended when you have lots of servers, or the message would be too long and hard to read.
## Example of setting the webhook
```bash
curl "https://api.telegram.org/bot${BOT_TOKEN}/setWebhook?url=https://your.frontend.com:5000/telegram/alpha+beta+gamma"
```
## Supported commands
- `path`: Show bird's ASN path to target IP
- `route`: Show bird's preferred route to target IP
- `trace`: Traceroute to target IP/domain
- `whois`: Whois query

33
frontend/Dockerfile Normal file
View File

@@ -0,0 +1,33 @@
FROM golang AS step_0
ENV CGO_ENABLED=0 GO111MODULE=on
WORKDIR /root
COPY . .
RUN go build -ldflags "-w -s" -o /frontend
################################################################################
FROM alpine:edge AS step_1
WORKDIR /root
RUN apk add --no-cache build-base pkgconf perl gettext \
libidn2-dev libidn2-static libunistring-dev libunistring-static gnu-libiconv-dev
RUN wget https://github.com/rfc1036/whois/archive/refs/tags/v5.5.18.tar.gz \
-O whois-5.5.18.tar.gz
RUN tar xvf whois-5.5.18.tar.gz \
&& cd whois-5.5.18 \
&& sed -i "s/#if defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L/#if 1/g" config.h \
&& make whois -j4 \
LDFLAGS="-static" CONFIG_FILE="/etc/whois.conf" PKG_CONFIG="pkg-config --static" HAVE_ICONV=1 \
&& strip /root/whois-5.5.18/whois
################################################################################
FROM scratch AS step_2
ENV PATH=/
ENV BIRDLG_WHOIS=/whois
COPY --from=step_0 /frontend /
COPY --from=step_1 /root/whois-5.5.18/whois /
COPY --from=step_1 /etc/services /etc/services
ENTRYPOINT ["/frontend"]

View File

@@ -1,13 +0,0 @@
FROM amd64/debian:buster
LABEL Lan Tian "lantian@lantian.pub"
ENV GOOS=linux GOARCH=amd64
WORKDIR /root
COPY . .
RUN apt-get -qq update && DEBIAN_FRONTEND=noninteractive apt-get -qq install -y golang git \
&& cd /root && go get github.com/gorilla/handlers && go build -o /frontend \
&& cd / && rm -rf /root/* \
&& apt-get -qq purge -y golang git \
&& apt-get -qq autoremove --purge -y && apt-get clean && rm -rf /var/lib/apt/lists
ENTRYPOINT ["/frontend"]

View File

@@ -1,13 +0,0 @@
FROM multiarch/debian-debootstrap:armhf-buster
LABEL Lan Tian "lantian@lantian.pub"
ENV GOOS=linux GOARCH=arm
WORKDIR /root
COPY . .
RUN apt-get -qq update && DEBIAN_FRONTEND=noninteractive apt-get -qq install -y golang git \
&& cd /root && go get github.com/gorilla/handlers && go build -o /frontend \
&& cd / && rm -rf /root/* \
&& apt-get -qq purge -y golang git \
&& apt-get -qq autoremove --purge -y && apt-get clean && rm -rf /var/lib/apt/lists
ENTRYPOINT ["/frontend"]

View File

@@ -1,13 +0,0 @@
FROM multiarch/debian-debootstrap:arm64-buster
LABEL Lan Tian "lantian@lantian.pub"
ENV GOOS=linux GOARCH=arm64
WORKDIR /root
COPY . .
RUN apt-get -qq update && DEBIAN_FRONTEND=noninteractive apt-get -qq install -y golang git \
&& cd /root && go get github.com/gorilla/handlers && go build -o /frontend \
&& cd / && rm -rf /root/* \
&& apt-get -qq purge -y golang git \
&& apt-get -qq autoremove --purge -y && apt-get clean && rm -rf /var/lib/apt/lists
ENTRYPOINT ["/frontend"]

View File

@@ -1,13 +0,0 @@
FROM i386/debian:buster
LABEL Lan Tian "lantian@lantian.pub"
ENV GOOS=linux GOARCH=386
WORKDIR /root
COPY . .
RUN apt-get -qq update && DEBIAN_FRONTEND=noninteractive apt-get -qq install -y golang git \
&& cd /root && go get github.com/gorilla/handlers && go build -o /frontend \
&& cd / && rm -rf /root/* \
&& apt-get -qq purge -y golang git \
&& apt-get -qq autoremove --purge -y && apt-get clean && rm -rf /var/lib/apt/lists
ENTRYPOINT ["/frontend"]

3
frontend/Makefile Normal file
View File

@@ -0,0 +1,3 @@
.PHONY: all
all:
go build -ldflags "-w -s" -o frontend

130
frontend/api.go Normal file
View File

@@ -0,0 +1,130 @@
package main
import (
"encoding/json"
"errors"
"net/http"
)
type apiRequest struct {
Servers []string `json:"servers"`
Type string `json:"type"`
Args string `json:"args"`
}
type apiGenericResultPair struct {
Server string `json:"server"`
Data string `json:"data"`
}
type apiSummaryResultPair struct {
Server string `json:"server"`
Data []SummaryRowData `json:"data"`
}
type apiResponse struct {
Error string `json:"error"`
Result []interface{} `json:"result"`
}
var apiHandlerMap = map[string](func(request apiRequest) apiResponse){
"summary": apiSummaryHandler,
"bird": apiGenericHandlerFactory("bird"),
"traceroute": apiGenericHandlerFactory("traceroute"),
"whois": apiWhoisHandler,
"server_list": apiServerListHandler,
}
func apiGenericHandlerFactory(endpoint string) func(request apiRequest) apiResponse {
return func(request apiRequest) apiResponse {
results := batchRequest(request.Servers, endpoint, request.Args)
var response apiResponse
for i, result := range results {
response.Result = append(response.Result, &apiGenericResultPair{
Server: request.Servers[i],
Data: result,
})
}
return response
}
}
func apiServerListHandler(request apiRequest) apiResponse {
var response apiResponse
for _, server := range setting.servers {
response.Result = append(response.Result, apiGenericResultPair{
Server: server,
})
}
return response
}
func apiSummaryHandler(request apiRequest) apiResponse {
results := batchRequest(request.Servers, "bird", "show protocols")
var response apiResponse
for i, result := range results {
parsedSummary, err := summaryParse(result, request.Servers[i])
if err != nil {
return apiResponse{
Error: err.Error(),
}
}
response.Result = append(response.Result, &apiSummaryResultPair{
Server: request.Servers[i],
Data: parsedSummary.Rows,
})
}
return response
}
func apiWhoisHandler(request apiRequest) apiResponse {
return apiResponse{
Error: "",
Result: []interface{}{
apiGenericResultPair{
Server: "",
Data: whois(request.Args),
},
},
}
}
func apiErrorHandler(err error) apiResponse {
return apiResponse{
Error: err.Error(),
}
}
func apiHandler(w http.ResponseWriter, r *http.Request) {
var request apiRequest
var response apiResponse
err := json.NewDecoder(r.Body).Decode(&request)
if err != nil {
response = apiResponse{
Error: err.Error(),
}
} else {
handler := apiHandlerMap[request.Type]
if handler == nil {
response = apiErrorHandler(errors.New("invalid request type"))
} else {
response = handler(request)
}
}
w.Header().Add("Content-Type", "application/json")
w.Header().Add("Access-Control-Allow-Origin", "*")
bytes, err := json.Marshal(response)
if err != nil {
println(err.Error())
return
}
w.Write(bytes)
}

207
frontend/api_test.go Normal file
View File

@@ -0,0 +1,207 @@
package main
import (
"bytes"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"github.com/jarcoal/httpmock"
"github.com/magiconair/properties/assert"
)
func TestApiServerListHandler(t *testing.T) {
setting.servers = []string{"alpha", "beta", "gamma"}
response := apiServerListHandler(apiRequest{})
assert.Equal(t, len(response.Result), 3)
assert.Equal(t, response.Result[0].(apiGenericResultPair).Server, "alpha")
assert.Equal(t, response.Result[1].(apiGenericResultPair).Server, "beta")
assert.Equal(t, response.Result[2].(apiGenericResultPair).Server, "gamma")
}
func TestApiGenericHandlerFactory(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpResponse := httpmock.NewStringResponder(200, BirdSummaryData)
httpmock.RegisterResponder("GET", "http://alpha:8000/bird?q="+url.QueryEscape("show protocols"), httpResponse)
setting.servers = []string{"alpha"}
setting.domain = ""
setting.proxyPort = 8000
request := apiRequest{
Servers: setting.servers,
Type: "bird",
Args: "show protocols",
}
handler := apiGenericHandlerFactory("bird")
response := handler(request)
assert.Equal(t, response.Error, "")
result := response.Result[0].(*apiGenericResultPair)
assert.Equal(t, result.Server, "alpha")
assert.Equal(t, result.Data, BirdSummaryData)
}
func TestApiSummaryHandler(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpResponse := httpmock.NewStringResponder(200, BirdSummaryData)
httpmock.RegisterResponder("GET", "http://alpha:8000/bird?q="+url.QueryEscape("show protocols"), httpResponse)
setting.servers = []string{"alpha"}
setting.domain = ""
setting.proxyPort = 8000
request := apiRequest{
Servers: setting.servers,
Type: "summary",
Args: "",
}
response := apiSummaryHandler(request)
assert.Equal(t, response.Error, "")
summary := response.Result[0].(*apiSummaryResultPair)
assert.Equal(t, summary.Server, "alpha")
// Protocol list will be sorted
assert.Equal(t, summary.Data[1].Name, "device1")
assert.Equal(t, summary.Data[1].Proto, "Device")
assert.Equal(t, summary.Data[1].Table, "---")
assert.Equal(t, summary.Data[1].State, "up")
assert.Equal(t, summary.Data[1].Since, "2021-08-27")
assert.Equal(t, summary.Data[1].Info, "")
}
func TestApiSummaryHandlerError(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpResponse := httpmock.NewStringResponder(200, "Mock backend error")
httpmock.RegisterResponder("GET", "http://alpha:8000/bird?q="+url.QueryEscape("show protocols"), httpResponse)
setting.servers = []string{"alpha"}
setting.domain = ""
setting.proxyPort = 8000
request := apiRequest{
Servers: setting.servers,
Type: "summary",
Args: "",
}
response := apiSummaryHandler(request)
assert.Equal(t, response.Error, "Mock backend error")
}
func TestApiWhoisHandler(t *testing.T) {
expectedData := "Mock Data"
server := WhoisServer{
t: t,
expectedQuery: "AS6939",
response: expectedData,
}
server.Listen()
go server.Run()
defer server.Close()
setting.whoisServer = server.server.Addr().String()
request := apiRequest{
Servers: []string{},
Type: "",
Args: "AS6939",
}
response := apiWhoisHandler(request)
assert.Equal(t, response.Error, "")
whoisResult := response.Result[0].(apiGenericResultPair)
assert.Equal(t, whoisResult.Server, "")
assert.Equal(t, whoisResult.Data, expectedData)
}
func TestApiErrorHandler(t *testing.T) {
err := errors.New("Mock Error")
response := apiErrorHandler(err)
assert.Equal(t, response.Error, "Mock Error")
}
func TestApiHandler(t *testing.T) {
setting.servers = []string{"alpha", "beta", "gamma"}
request := apiRequest{
Servers: []string{},
Type: "server_list",
Args: "",
}
requestJson, err := json.Marshal(request)
if err != nil {
t.Error(err)
}
r := httptest.NewRequest(http.MethodGet, "/api", bytes.NewReader(requestJson))
w := httptest.NewRecorder()
apiHandler(w, r)
var response apiResponse
err = json.Unmarshal(w.Body.Bytes(), &response)
if err != nil {
t.Error(err)
}
assert.Equal(t, len(response.Result), 3)
// Hard to unmarshal JSON into apiGenericResultPair objects, won't check here
}
func TestApiHandlerBadJSON(t *testing.T) {
setting.servers = []string{"alpha", "beta", "gamma"}
r := httptest.NewRequest(http.MethodGet, "/api", strings.NewReader("{bad json}"))
w := httptest.NewRecorder()
apiHandler(w, r)
var response apiResponse
err := json.Unmarshal(w.Body.Bytes(), &response)
if err != nil {
t.Error(err)
}
assert.Equal(t, len(response.Result), 0)
}
func TestApiHandlerInvalidType(t *testing.T) {
setting.servers = []string{"alpha", "beta", "gamma"}
request := apiRequest{
Servers: setting.servers,
Type: "invalid_type",
Args: "",
}
requestJson, err := json.Marshal(request)
if err != nil {
t.Error(err)
}
r := httptest.NewRequest(http.MethodGet, "/api", bytes.NewReader(requestJson))
w := httptest.NewRecorder()
apiHandler(w, r)
var response apiResponse
err = json.Unmarshal(w.Body.Bytes(), &response)
if err != nil {
t.Error(err)
}
assert.Equal(t, len(response.Result), 0)
}

83
frontend/asn_cache.go Normal file
View File

@@ -0,0 +1,83 @@
package main
import (
"fmt"
"net"
"strings"
)
type ASNCache map[string]string
func (cache ASNCache) _lookup(asn string) string {
// Try to get ASN representation using DNS
if setting.dnsInterface != "" {
records, err := net.LookupTXT(fmt.Sprintf("AS%s.%s", asn, setting.dnsInterface))
if err == nil {
result := strings.Join(records, " ")
if resultSplit := strings.Split(result, " | "); len(resultSplit) > 1 {
result = strings.Join(resultSplit[1:], "\n")
}
return fmt.Sprintf("AS%s\n%s", asn, result)
}
}
// Try to get ASN representation using WHOIS
if setting.whoisServer != "" {
if setting.bgpmapInfo == "" {
setting.bgpmapInfo = "asn,as-name,ASName,descr"
}
records := whois(fmt.Sprintf("AS%s", asn))
if records != "" {
recordsSplit := strings.Split(records, "\n")
var result []string
for _, title := range strings.Split(setting.bgpmapInfo, ",") {
if title == "asn" {
result = append(result, "AS"+asn)
}
}
for _, title := range strings.Split(setting.bgpmapInfo, ",") {
allow_multiline := false
if title[0] == ':' && len(title) >= 2 {
title = title[1:]
allow_multiline = true
}
for _, line := range recordsSplit {
if len(line) == 0 || line[0] == '%' || !strings.Contains(line, ":") {
continue
}
linearr := strings.SplitN(line, ":", 2)
line_title := linearr[0]
content := strings.TrimSpace(linearr[1])
if line_title != title {
continue
}
result = append(result, content)
if !allow_multiline {
break
}
}
}
if len(result) > 0 {
return strings.Join(result, "\n")
}
}
}
return ""
}
func (cache ASNCache) Lookup(asn string) string {
cachedValue, cacheOk := cache[asn]
if cacheOk {
return cachedValue
}
result := cache._lookup(asn)
if len(result) == 0 {
result = fmt.Sprintf("AS%s", asn)
}
cache[asn] = result
return result
}

View File

@@ -0,0 +1,52 @@
package main
import (
"strings"
"testing"
"github.com/magiconair/properties/assert"
)
func TestGetASNRepresentationDNS(t *testing.T) {
checkNetwork(t)
setting.dnsInterface = "asn.cymru.com"
setting.whoisServer = ""
cache := make(ASNCache)
result := cache.Lookup("6939")
if !strings.Contains(result, "HURRICANE") {
t.Errorf("Lookup AS6939 failed, got %s", result)
}
}
func TestGetASNRepresentationDNSFallback(t *testing.T) {
checkNetwork(t)
setting.dnsInterface = "invalid.example.com"
setting.whoisServer = "whois.arin.net"
cache := make(ASNCache)
result := cache.Lookup("6939")
if !strings.Contains(result, "HURRICANE") {
t.Errorf("Lookup AS6939 failed, got %s", result)
}
}
func TestGetASNRepresentationWhois(t *testing.T) {
checkNetwork(t)
setting.dnsInterface = ""
setting.whoisServer = "whois.arin.net"
cache := make(ASNCache)
result := cache.Lookup("6939")
if !strings.Contains(result, "HURRICANE") {
t.Errorf("Lookup AS6939 failed, got %s", result)
}
}
func TestGetASNRepresentationFallback(t *testing.T) {
setting.dnsInterface = ""
setting.whoisServer = ""
cache := make(ASNCache)
result := cache.Lookup("6939")
assert.Equal(t, result, "AS6939")
}

BIN
frontend/assets/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -0,0 +1,2 @@
User-agent: *
Disallow: /

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,73 @@
// adapted from https://stackoverflow.com/a/57080195
document.querySelectorAll('table.sortable')
.forEach((table)=> {
table.querySelectorAll('th')
.forEach((element, columnNo) => {
element.addEventListener('click', event => {
if(element.classList.contains('ascSorted')) {
dir = -1;
element.classList.remove('ascSorted');
element.classList.add('descSorted');
element.innerText = element.innerText.slice(0,-2) + " ↓";
} else if(element.classList.contains('descSorted')) {
dir = 1;
element.classList.remove('descSorted');
element.classList.add('ascSorted');
element.innerText = element.innerText.slice(0,-2) + " ↑";
} else {
dir = 1;
element.classList.add('ascSorted');
element.innerText += " ↑";
}
sortTable(table, columnNo, 0, dir, 1);
});
});
});
function sortTable(table, priCol, secCol, priDir, secDir) {
const tableBody = table.querySelector('tbody');
const tableData = table2data(tableBody);
tableData.sort((a, b) => {
if(a[priCol] === b[priCol]) {
if(a[secCol] > b[secCol]) {
return secDir;
} else {
return -secDir;
}
} else if(a[priCol] > b[priCol]) {
return priDir;
} else {
return -priDir;
}
});
data2table(tableBody, tableData);
}
function table2data(tableBody) {
const tableData = [];
tableBody.querySelectorAll('tr')
.forEach(row => {
const rowData = [];
row.querySelectorAll('td')
.forEach(cell => {
rowData.push(cell.innerHTML);
});
rowData.classList = row.classList.toString();
tableData.push(rowData);
});
return tableData;
}
function data2table(tableBody, tableData) {
tableBody.querySelectorAll('tr')
.forEach((row, i) => {
const rowData = tableData[i];
row.classList = rowData.classList;
row.querySelectorAll('td')
.forEach((cell, j) => {
cell.innerHTML = rowData[j];
});
tableData.push(rowData);
});
}

View File

@@ -0,0 +1,16 @@
<h2>BGPmap: {{ html .Target }}</h2>
<div id="bgpmap">
</div>
<script src="/static/jsdelivr/npm/viz.js@2.1.2/viz.min.js" crossorigin="anonymous"></script>
<script src="/static/jsdelivr/npm/viz.js@2.1.2/lite.render.js" crossorigin="anonymous"></script>
<script>
var viz = new Viz();
viz.renderSVGElement(atob({{ .Result }}))
.then(element => {
document.getElementById("bgpmap").appendChild(element);
})
.catch(error => {
document.getElementById("bgpmap").innerHTML = "<pre>"+error+"</pre>"
});
</script>

View File

@@ -0,0 +1,2 @@
<h2>{{ html .ServerName }}: {{ html .Target }}</h2>
{{ .Result }}

View File

@@ -0,0 +1,100 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="renderer" content="webkit">
<title>{{ html .Title }}</title>
<link rel="stylesheet" href="/static/jsdelivr/npm/bootstrap@4.5.1/dist/css/bootstrap.min.css" integrity="sha256-VoFZSlmyTXsegReQCNmbXrS4hBBUl/cexZvPmPWoJsY=" crossorigin="anonymous">
<meta name="robots" content="noindex, nofollow">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="{{ .BrandURL }}">{{ .Brand }}</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
{{ $option := .URLOption }}
{{ $server := .URLServer }}
{{ $target := .URLCommand }}
{{ if .IsWhois }}
{{ $option = "summary" }}
{{ $server = .AllServersURL }}
{{ $target = "" }}
{{ end }}
<ul class="navbar-nav mr-auto">
<li class="nav-item">
{{ if eq .AllServersURLCustom "all" }}
<a class="nav-link{{ if .AllServersLinkActive }} active{{ end }}"
href="/{{ $option }}/{{ .AllServersURL }}/{{ $target }}"> {{ .AllServerTitle }} </a>
{{ else }}
<a class="nav-link active"
href="{{ .AllServersURLCustom }}"> {{ .AllServerTitle }} </a>
{{ end }}
</li>
{{ $length := len .Servers }}
{{ range $k, $v := .Servers }}
<li class="nav-item">
{{ if gt $length 1 }}
<a class="nav-link{{ if eq $server $v }} active{{ end }}"
href="/{{ $option }}/{{ $v }}/{{ $target }}">{{ html (index $.ServersDisplay $k) }}</a>
{{ else }}
<a class="nav-link{{ if eq $server $v }} active{{ end }}"
href="/">{{ html (index $.ServersDisplay $k) }}</a>
{{ end }}
</li>
{{ end }}
</ul>
{{ if .IsWhois }}
{{ $target = .WhoisTarget }}
{{ end }}
<form name="goto" class="form-inline" action="javascript:goto();">
<div class="input-group">
<select name="action" class="form-control">
{{ range $k, $v := .Options }}
<option value="{{ html $k }}"{{ if eq $k $.URLOption }} selected{{end}}>{{ html $v }}</option>
{{ end }}
</select>
<input name="server" class="d-none" value="{{ html ($server | pathescape) }}">
<input name="target" class="form-control" placeholder="Target" aria-label="Target" value="{{ html $target }}">
<div class="input-group-append">
<button class="btn btn-outline-success" type="submit">&raquo;</button>
</div>
</div>
</form>
</div>
</nav>
<div class="container">
{{ .Content }}
</div>
<script src="/static/jsdelivr/npm/jquery@3.5.1/dist/jquery.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="/static/jsdelivr/npm/bootstrap@4.5.1/dist/js/bootstrap.min.js" integrity="sha256-0IiaoZCI++9oAAvmCb5Y0r93XkuhvJpRalZLffQXLok=" crossorigin="anonymous"></script>
<script src="/static/sortTable.js"></script>
<script>
function goto() {
let action = $('[name="action"]').val();
let server = $('[name="server"]').val();
let target = $('[name="target"]').val();
let url = "";
if (action == "whois") {
url = "/" + action + "/" + target;
} else if (action == "summary") {
url = "/" + action + "/" + server + "/";
} else {
url = "/" + action + "/" + server + "/" + target;
}
window.location.href = url;
}
</script>
</body>
</html>

View File

@@ -0,0 +1,21 @@
{{ $ServerName := urlquery .ServerName }}
<table class="table table-striped table-bordered table-sm sortable">
<thead>
{{ range .Header }}
<th scope="col">{{ html . }}</th>
{{ end }}
</thead>
<tbody>
{{ range .Rows }}
<tr class="table-{{ .MappedState }}">
<td><a href="/detail/{{ $ServerName }}/{{ urlquery .Name }}">{{ html .Name }}</a></td>
<td>{{ html .Proto }}</td>
<td>{{ html .Table }}</td>
<td>{{ html .State }}</td>
<td>{{ html .Since }}</td>
<td>{{ html .Info }}</td>
</tr>
{{ end }}
</tbody>
</table>

Some files were not shown because too many files have changed in this diff Show More