You've already forked bird-lg-go
							
							
				mirror of
				https://github.com/xddxdd/bird-lg-go
				synced 2025-10-30 09:40:51 +01:00 
			
		
		
		
	Compare commits
	
		
			107 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 47c66b125c | ||
|   | 9e17b116f1 | ||
|   | 335ad40634 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 6ec0f2e7a6 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 4b73cf0fcb | ||
|   | 3b1d001543 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 675cb26ed1 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 556d3e50d3 | ||
|   | 06796f546e | ||
|   | d029d6684c | ||
|   | 5ce0f55f35 | ||
|   | 890ab51b07 | ||
|   | 8e4a35cc8c | ||
|   | 97f3c6088f | ||
|   | 982326a678 | ||
|   | 4b3980f6bd | ||
|   | 6f6b2bd283 | ||
|   | 892a7bee22 | ||
|   | 348295b9aa | ||
|   | 950c018b18 | ||
|   | 26efeb4996 | ||
|   | 5a5dfbc93f | ||
|   | f60a292129 | ||
|   | e7f6026854 | ||
|   | a4e0f4c193 | ||
|   | af5b653326 | ||
|   | 58847759b3 | ||
|   | 6481e7cc8d | ||
|   | 2166d73b3d | ||
|   | a64d839e2c | ||
|   | 1a3c618522 | ||
|   | fbd190628c | ||
|   | 823b639245 | ||
|   | b0c0e5442d | ||
|   | 4e4ce89418 | ||
|   | 234aadadd9 | ||
|   | bee26f421c | ||
|   | 2e0cb131ca | ||
|   | 4c248c638a | ||
|   | 3550362a4d | ||
|   | 256a80646f | ||
|   | 03c42eb1e8 | ||
|   | aea85e774c | ||
|   | 80d9351a58 | ||
|   | 5e0bc081e6 | ||
|   | 4d53d1f095 | ||
|   | 5883015294 | ||
|   | 80e66a7a81 | ||
|   | 41329da7cb | ||
|   | 8e56705205 | ||
|   | 6a8b3a0e55 | ||
|   | 83ab403706 | ||
|   | 7c7814cc7b | ||
|   | 8598060cc0 | ||
|   | bda06ddd5e | ||
|   | f404072ab8 | ||
| ![dependabot-preview[bot]](/assets/img/avatar_default.png)  | fa827502cf | ||
|   | 794125a96f | ||
|   | de9d9101b1 | ||
|   | 056ef3769e | ||
|   | 974e809deb | ||
|   | 6e19b5ae64 | ||
|   | 874089117b | ||
|   | f77a8a28fe | ||
|   | 9e8a845658 | ||
|   | fd3e7b8379 | ||
|   | 8765189deb | ||
|   | 492942cce1 | ||
|   | f81a5308ae | ||
|   | 5b5a09ccbd | ||
|   | dc4d7e6532 | ||
|   | 28a7d2a53f | ||
|   | 4413f1032f | ||
|   | 007b66e036 | ||
|   | 3f612d2e76 | ||
|   | f49f8bac5e | ||
|   | f6ddc5761b | ||
|   | 1c3d9ec594 | ||
|   | 6cc0c617b4 | ||
|   | e2cc580da3 | ||
|   | 472cec74b0 | ||
|   | da2c3d9aed | ||
|   | aa76bc3de7 | ||
|   | a984095282 | ||
|   | 1baf325149 | ||
|   | 72946e1113 | ||
|   | 90e5012840 | ||
|   | 8d5eb56199 | ||
|   | 8d0618fed9 | ||
|   | f8ea511d44 | ||
|   | b99eb60c30 | ||
|   | 9f934ca53c | ||
|   | ee7cc1675b | ||
|   | f4b6955343 | ||
|   | 78ce724171 | ||
|   | 6179c688be | ||
|   | 8d0e210572 | ||
|   | 26c51176e4 | ||
|   | 5cf2ac57b8 | ||
|   | 75bc63ffa7 | ||
|   | 438c6a1f82 | ||
|   | b98d783739 | ||
|   | 5000ad1bbf | ||
|   | 538699ccd2 | ||
|   | 9e77de6b46 | ||
|   | c15942cc32 | ||
|   | 3bcfc3d36c | 
							
								
								
									
										127
									
								
								.circleci/config.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								.circleci/config.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | ||||
| version: 2.1 | ||||
|  | ||||
| workflows: | ||||
|   docker: | ||||
|     jobs: | ||||
|       - build | ||||
|       - docker-frontend-deploy: | ||||
|           context: | ||||
|             - docker | ||||
|           requires: | ||||
|             - build | ||||
|           filters: | ||||
|             branches: | ||||
|               only: master | ||||
|       - docker-proxy-deploy: | ||||
|           context: | ||||
|             - docker | ||||
|           requires: | ||||
|             - build | ||||
|           filters: | ||||
|             branches: | ||||
|               only: master | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|     docker: | ||||
|       - image: cimg/go:1.17 | ||||
|     working_directory: /home/circleci/go/src/github.com/xddxdd/bird-lg-go | ||||
|     steps: | ||||
|       - checkout | ||||
|       - run:  | ||||
|           name: Test frontend | ||||
|           command: | | ||||
|             export GO111MODULE=on | ||||
|             cd frontend | ||||
|             go get -v -t -d ./... | ||||
|             go test -v ./... | ||||
|       - run:  | ||||
|           name: Test proxy | ||||
|           command: | | ||||
|             export GO111MODULE=on | ||||
|             cd proxy | ||||
|             go get -v -t -d ./... | ||||
|             go test -v ./... | ||||
|  | ||||
|   docker-frontend-deploy: | ||||
|     machine: | ||||
|       image: ubuntu-2004:202111-02 | ||||
|     environment: | ||||
|       BUILDX_PLATFORMS: linux/amd64,linux/arm64,linux/386,linux/arm/v7 | ||||
|     steps: | ||||
|       - checkout | ||||
|       - run: | ||||
|           name: Install buildx | ||||
|           command: | | ||||
|             BUILDX_BINARY_URL="https://github.com/docker/buildx/releases/download/v0.7.1/buildx-v0.7.1.linux-amd64" | ||||
|  | ||||
|             curl --output docker-buildx \ | ||||
|               --silent --show-error --location --fail --retry 3 \ | ||||
|               "$BUILDX_BINARY_URL" | ||||
|  | ||||
|             mkdir -p ~/.docker/cli-plugins | ||||
|  | ||||
|             mv docker-buildx ~/.docker/cli-plugins/ | ||||
|             chmod a+x ~/.docker/cli-plugins/docker-buildx | ||||
|  | ||||
|             docker buildx install | ||||
|             # Run binfmt | ||||
|             docker run --rm --privileged multiarch/qemu-user-static --reset -p yes | ||||
|       - run: | ||||
|           name: Build Docker image | ||||
|           environment: | ||||
|             BUILD_ID: << pipeline.number >> | ||||
|           command: | | ||||
|             echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin | ||||
|             docker buildx create --name mybuilder --use | ||||
|             docker buildx build \ | ||||
|               --platform $BUILDX_PLATFORMS \ | ||||
|               -t $DOCKER_USERNAME/bird-lg-go:circleci-build$BUILD_ID \ | ||||
|               --progress plain \ | ||||
|               --push frontend | ||||
|             docker buildx build \ | ||||
|               --platform $BUILDX_PLATFORMS \ | ||||
|               -t $DOCKER_USERNAME/bird-lg-go:latest \ | ||||
|               --progress plain \ | ||||
|               --push frontend | ||||
|  | ||||
|   docker-proxy-deploy: | ||||
|     machine: | ||||
|       image: ubuntu-2004:202111-02 | ||||
|     environment: | ||||
|       BUILDX_PLATFORMS: linux/amd64,linux/arm64,linux/386,linux/arm/v7 | ||||
|     steps: | ||||
|       - checkout | ||||
|       - run: | ||||
|           name: Install buildx | ||||
|           command: | | ||||
|             BUILDX_BINARY_URL="https://github.com/docker/buildx/releases/download/v0.7.1/buildx-v0.7.1.linux-amd64" | ||||
|  | ||||
|             curl --output docker-buildx \ | ||||
|               --silent --show-error --location --fail --retry 3 \ | ||||
|               "$BUILDX_BINARY_URL" | ||||
|  | ||||
|             mkdir -p ~/.docker/cli-plugins | ||||
|  | ||||
|             mv docker-buildx ~/.docker/cli-plugins/ | ||||
|             chmod a+x ~/.docker/cli-plugins/docker-buildx | ||||
|  | ||||
|             docker buildx install | ||||
|             # Run binfmt | ||||
|             docker run --rm --privileged multiarch/qemu-user-static --reset -p yes | ||||
|       - run: | ||||
|           name: Build Docker image | ||||
|           environment: | ||||
|             BUILD_ID: << pipeline.number >> | ||||
|           command: | | ||||
|             echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin | ||||
|             docker buildx create --name mybuilder --use | ||||
|             docker buildx build \ | ||||
|               --platform $BUILDX_PLATFORMS \ | ||||
|               -t $DOCKER_USERNAME/bird-lgproxy-go:circleci-build$BUILD_ID \ | ||||
|               --push proxy | ||||
|             docker buildx build \ | ||||
|               --platform $BUILDX_PLATFORMS \ | ||||
|               -t $DOCKER_USERNAME/bird-lgproxy-go:latest \ | ||||
|               --progress plain \ | ||||
|               --push proxy | ||||
							
								
								
									
										16
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal 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 | ||||
							
								
								
									
										35
									
								
								.github/workflows/release.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								.github/workflows/release.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| on: | ||||
|   release: | ||||
|     types: [created] | ||||
|  | ||||
| jobs: | ||||
|   releases-matrix: | ||||
|     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: | ||||
|     - uses: actions/checkout@v3 | ||||
|     - uses: wangyoucao577/go-release-action@v1.30 | ||||
|       with: | ||||
|         github_token: ${{ secrets.GITHUB_TOKEN }} | ||||
|         goos: ${{ matrix.goos }} | ||||
|         goarch: ${{ matrix.goarch }} | ||||
|         project_path: "./frontend" | ||||
|         binary_name: "bird-lg-go" | ||||
|     - uses: wangyoucao577/go-release-action@v1.30 | ||||
|       with: | ||||
|         github_token: ${{ secrets.GITHUB_TOKEN }} | ||||
|         goos: ${{ matrix.goos }} | ||||
|         goarch: ${{ matrix.goarch }} | ||||
|         project_path: "./proxy" | ||||
|         binary_name: "bird-lgproxy-go" | ||||
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -17,3 +17,10 @@ | ||||
| .DS_Store | ||||
| frontend/frontend | ||||
| proxy/proxy | ||||
|  | ||||
| # don't include generated bindata file | ||||
| frontend/bindata.go | ||||
|  | ||||
| # don't include generated Dockerfiles | ||||
| frontend/Dockerfile.* | ||||
| proxy/Dockerfile.* | ||||
							
								
								
									
										35
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -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
									
								
							
							
						
						
									
										13
									
								
								Makefile
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										169
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										169
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,10 +1,43 @@ | ||||
| Bird-lg-go | ||||
| ========== | ||||
| # Bird-lg-go | ||||
|  | ||||
| An alternative implementation for [bird-lg](https://github.com/sileht/bird-lg) written in Go. Both frontend and backend (proxy) are implemented, and can work with either the original Python implementation or the Go implementation. | ||||
|  | ||||
| Frontend | ||||
| -------- | ||||
| > The code on master branch no longer support BIRDv1. Branch "bird1" is the last version that supports BIRDv1. | ||||
|  | ||||
| ## Table of Contents | ||||
|  | ||||
| - [Bird-lg-go](#bird-lg-go) | ||||
|   - [Table of Contents](#table-of-contents) | ||||
|   - [Build Instructions](#build-instructions) | ||||
|     - [Build Docker Images](#build-docker-images) | ||||
|   - [Frontend](#frontend) | ||||
|   - [Proxy](#proxy) | ||||
|   - [Advanced Features](#advanced-features) | ||||
|     - [Display names](#display-names) | ||||
|     - [IP addresses](#ip-addresses) | ||||
|     - [API](#api) | ||||
|     - [Telegram Bot Webhook](#telegram-bot-webhook) | ||||
|   - [Credits](#credits) | ||||
|   - [License](#license) | ||||
|  | ||||
| ## Build Instructions | ||||
|  | ||||
| You need to have **Go 1.16 or newer** installed on your machine. | ||||
|  | ||||
| Run `make` to build binaries for both the frontend and the proxy. | ||||
|  | ||||
| Optionally run `make install` to install them to `/usr/local/bin` (`bird-lg-go` and `bird-lgproxy-go`). | ||||
|  | ||||
| ### Build Docker Images | ||||
|  | ||||
| Use the Dockerfiles in `frontend` and `proxy` directory. | ||||
|  | ||||
| Ready-to-use images are available at: | ||||
|  | ||||
| - Frontend: <https://hub.docker.com/r/xddxdd/bird-lg-go> | ||||
| - Proxy: <https://hub.docker.com/r/xddxdd/bird-lgproxy-go> | ||||
|  | ||||
| ## Frontend | ||||
|  | ||||
| The frontend directory contains the code for the web frontend, where users see BGP states, do traceroutes and whois, etc. It's a replacement for "lg.py" in original bird-lg project. | ||||
|  | ||||
| @@ -16,21 +49,46 @@ Features implemented: | ||||
| - Work with both Python proxy (lgproxy.py) and Go proxy (proxy dir of this project) | ||||
| - Visualize AS paths as picture (bgpmap feature) | ||||
|  | ||||
| Usage: all configuration is done via commandline parameters or environment variables, no config file. | ||||
| Configuration can be set in: | ||||
|  | ||||
| - --servers / BIRDLG_SERVERS: server name prefixes, separated by comma | ||||
| - --domain / BIRDLG_DOMAIN: server name domain suffixes | ||||
| - --listen / BIRDLG_LISTEN: address bird-lg is listening on (default ":5000") | ||||
| - --proxy-port / BIRDLG_PROXY_PORT: port bird-lgproxy is running on (default 8000) | ||||
| - --whois / BIRDLG_WHOIS: whois server for queries (default "whois.verisign-grs.com") | ||||
| - `bird-lg.[json/yaml/etc]` in current directory | ||||
| - `/etc/bird-lg/bird-lg.[json/yaml/etc]` | ||||
| - Commandline parameter | ||||
| - Environment variables | ||||
|  | ||||
| Configuration is handled by [viper](https://github.com/spf13/viper), any config format supported by it can be used. | ||||
|  | ||||
| > Note: the config system is replaced with viper only recently (2022-07-08). If some config items do not work, please open an issue, and use commit [892a7bee22a1bb02d3b4da6d270c65b6e4e1321a](https://github.com/xddxdd/bird-lg-go/tree/892a7bee22a1bb02d3b4da6d270c65b6e4e1321a) (last version before config system replace) for the time being. | ||||
|  | ||||
| | Config Key | Parameter | Environment Variable | Description | | ||||
| | ---------- | --------- | -------------------- | ----------- | | ||||
| | servers | --servers | BIRDLG_SERVERS | server name prefixes, separated by comma | | ||||
| | domain | --domain | BIRDLG_DOMAIN | server name domain suffixes | | ||||
| | listen | --listen | BIRDLG_LISTEN | address bird-lg is listening on (default "5000") | | ||||
| | proxy_port | --proxy-port | BIRDLG_PROXY_PORT | port bird-lgproxy is running on (default 8000) | | ||||
| | whois | --whois | BIRDLG_WHOIS | whois server for queries (default "whois.verisign-grs.com"). Start with "/" to spacify local whois binary("/usr/local/whois"). | | ||||
| | dns_interface | --dns-interface | BIRDLG_DNS_INTERFACE | dns zone to query ASN information (default "asn.cymru.com") | | ||||
| | bgpmap_info | --bgpmap-info | BIRDLG_BGPMAP_INFO | the infos displayed in bgpmap, separated by comma, start with `:` means allow multiline (default "asn,as-name,ASName,descr") | | ||||
| | title_brand | --title-brand | BIRDLG_TITLE_BRAND | prefix of page titles in browser tabs (default "Bird-lg Go") | | ||||
| | navbar_brand | --navbar-brand | BIRDLG_NAVBAR_BRAND | brand to show in the navigation bar (default "Bird-lg Go") | | ||||
| | navbar_brand_url | --navbar-brand-url | BIRDLG_NAVBAR_BRAND_URL | the url of the brand to show in the navigation bar (default "/") | | ||||
| | navbar_all_servers | --navbar-all-servers | BIRDLG_NAVBAR_ALL_SERVERS | the text of "All servers" button in the navigation bar (default "ALL Servers") | | ||||
| | navbar_all_url | --navbar-all-url | BIRDLG_NAVBAR_ALL_URL | the URL of "All servers" button (default "all") | | ||||
| | net_specific_mode | --net-specific-mode | BIRDLG_NET_SPECIFIC_MODE | apply network-specific changes for some networks, use "dn42" for BIRD in dn42 network | | ||||
| | protocol_filter | --protocol-filter | BIRDLG_PROTOCOL_FILTER | protocol types to show in summary tables (comma separated list); defaults to all if not set | | ||||
| | name_filter | --name-filter | BIRDLG_NAME_FILTER | protocol names to hide in summary tables (RE2 syntax); defaults to none if not set | | ||||
| | timeout | --time-out | BIRDLG_TIMEOUT | time before request timed out, in seconds; defaults to 120 if not set | | ||||
|  | ||||
| Example: the following command starts the frontend with 2 BIRD nodes, with domain name "gigsgigscloud.dn42.lantian.pub" and "hostdare.dn42.lantian.pub", and proxies are running on port 8000 on both nodes. | ||||
|  | ||||
|     ./frontend --servers=gigsgigscloud,hostdare --domain=dn42.lantian.pub --proxy-port=8000 | ||||
| ```bash | ||||
| ./frontend --servers=gigsgigscloud,hostdare --domain=dn42.lantian.pub --proxy-port=8000 | ||||
| ``` | ||||
|  | ||||
| Example: the following docker-compose.yml entry does the same as above, but by starting a Docker container: | ||||
|  | ||||
|     services: | ||||
| ```yaml | ||||
| services: | ||||
|   bird-lg: | ||||
|     image: xddxdd/bird-lg-go | ||||
|     container_name: bird-lg | ||||
| @@ -40,59 +98,110 @@ Example: the following docker-compose.yml entry does the same as above, but by s | ||||
|       - BIRDLG_DOMAIN=dn42.lantian.pub | ||||
|     ports: | ||||
|       - "5000:5000" | ||||
| ``` | ||||
|  | ||||
| Demo: https://lg.lantian.pub | ||||
| Demo: <https://lg.lantian.pub> | ||||
|  | ||||
| Proxy | ||||
| ----- | ||||
| ## Proxy | ||||
|  | ||||
| The proxy directory contains the code for the "proxy" for bird commands and traceroutes. It's a replacement for "lgproxy.py" in original bird-lg project. | ||||
|  | ||||
| Features implemented: | ||||
|  | ||||
| - Sending queries to BIRD and BIRD6 | ||||
|   - If you are using BIRDv2, simply point both `--bird` and `--bird6` to the only socket file of BIRDv2 | ||||
| - Sending queries to BIRD | ||||
| - Sending "restrict" command to BIRD to prevent unauthorized changes | ||||
| - Executing traceroute command on Linux, FreeBSD and OpenBSD | ||||
| - Source IP restriction | ||||
|  | ||||
| Usage: all configuration is done via commandline parameters or environment variables, no config file. | ||||
| Configuration can be set in: | ||||
|  | ||||
| - --allowed / ALLOWED_IPS: IPs allowed to access this proxy, separated by commas. Don't set to allow all IPs. (default "") | ||||
| - --bird / BIRD_SOCKET: socket file for bird, set either in parameter or environment variable BIRD_SOCKET (default "/var/run/bird/bird.ctl") | ||||
| - --bird6 / BIRD6_SOCKET: socket file for bird6, set either in parameter or environment variable BIRD6_SOCKET (default "/var/run/bird/bird6.ctl") | ||||
| - --listen / BIRDLG_LISTEN: listen address, set either in parameter or environment variable BIRDLG_LISTEN (default ":8000") | ||||
| - `bird-lgproxy.[json/yaml/etc]` in current directory | ||||
| - `/etc/bird-lg/bird-lgproxy.[json/yaml/etc]` | ||||
| - Commandline parameter | ||||
| - Environment variables | ||||
|  | ||||
| Configuration is handled by [viper](https://github.com/spf13/viper), any config format supported by it can be used. | ||||
|  | ||||
| > Note: the config system is replaced with viper only recently (2022-07-08). If some config items do not work, please open an issue, and use commit [892a7bee22a1bb02d3b4da6d270c65b6e4e1321a](https://github.com/xddxdd/bird-lg-go/tree/892a7bee22a1bb02d3b4da6d270c65b6e4e1321a) (last version before config system replace) for the time being. | ||||
|  | ||||
| | Config Key | Parameter | Environment Variable | Description | | ||||
| | ---------- | --------- | -------------------- | ----------- | | ||||
| | allowed_ips | --allowed | ALLOWED_IPS | IPs allowed to access this proxy, separated by commas. Don't set to allow all IPs. (default "") | | ||||
| | bird_socket | --bird | BIRD_SOCKET | socket file for bird, set either in parameter or environment variable BIRD_SOCKET (default "/var/run/bird/bird.ctl") | | ||||
| | listen | --listen | BIRDLG_PROXY_PORT | listen address, set either in parameter or environment variable  BIRDLG_PROXY_PORT(default "8000") | | ||||
| | traceroute_bin | --traceroute_bin | BIRDLG_TRACEROUTE_BIN | traceroute binary file, set either in parameter or environment variable  BIRDLG_TRACEROUTE_BIN(default "traceroute") | | ||||
| | traceroute_raw | --traceroute_raw | BIRDLG_TRACEROUTE_RAW | whether to display traceroute outputs raw (default false) | | ||||
|  | ||||
| Example: start proxy with default configuration, should work "out of the box" on Debian 9 with BIRDv1: | ||||
|  | ||||
|     ./proxy | ||||
| ```bash | ||||
| ./proxy | ||||
| ``` | ||||
|  | ||||
| Example: start proxy with custom bird socket location: | ||||
|  | ||||
|     ./proxy --bird /run/bird.ctl --bird6 /run/bird6.ctl | ||||
| ```bash | ||||
| ./proxy --bird /run/bird.ctl | ||||
| ``` | ||||
|  | ||||
| Example: the following docker-compose.yml entry does the same as above, but by starting a Docker container: | ||||
|  | ||||
| ```yaml | ||||
| services: | ||||
|   bird-lgproxy: | ||||
|     image: xddxdd/bird-lgproxy-go | ||||
|     container_name: bird-lgproxy | ||||
|     restart: always | ||||
|     volumes: | ||||
|       - "/run/bird.ctl:/var/run/bird/bird.ctl" | ||||
|         - "/run/bird6.ctl:/var/run/bird/bird6.ctl" | ||||
|     ports: | ||||
|       - "192.168.0.1:8000:8000" | ||||
| ``` | ||||
|  | ||||
| You can use source IP restriction to increase security. You should also bind the proxy to a specific interface and use an external firewall/iptables for added security. | ||||
|  | ||||
| Credits | ||||
| ------- | ||||
| ## Advanced Features | ||||
|  | ||||
| ### Display names | ||||
|  | ||||
| The server parameter is composed of server name prefixes, separated by comma. It also supports an extended syntax: It allows to define display names for the user interface that are different from the actual server names. | ||||
|  | ||||
| For instance, the two servers from the basic example can be displayed as "Gigs" and "Hostdare" using the following syntax (as known from email addresses): | ||||
|  | ||||
| ```bash | ||||
| ./frontend --servers="Gigs<gigsgigscloud>,Hostdare<hostdare>" --domain=dn42.lantian.pub | ||||
| ``` | ||||
|  | ||||
| ### IP addresses | ||||
|  | ||||
| You may also specify IP addresses as server names when no domain is specified. IPv6 link local addresses are supported, too. | ||||
|  | ||||
| For example: | ||||
|  | ||||
| ```bash | ||||
| ./frontend --servers="Prod<prod.mydomain.local>,Test1<fd88:dead:beef::1>,Test2<fe80::c%wg0>" --domain= | ||||
| ``` | ||||
|  | ||||
| These three servers are displayed as "Prod", "Test1" and "Test2" in the user interface. | ||||
|  | ||||
| ### API | ||||
|  | ||||
| The frontend provides an API for running BIRD/traceroute/whois queries. | ||||
|  | ||||
| See [API docs](docs/API.md) for detailed information. | ||||
|  | ||||
| ### 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. | ||||
|  | ||||
| See [Telegram docs](docs/Telegram.md) for detailed information. | ||||
|  | ||||
| ## Credits | ||||
|  | ||||
| - Everyone who contributed to this project (see Contributors section on the right) | ||||
| - Mehdi Abaakouk for creating [the original bird-lg project](https://github.com/sileht/bird-lg) | ||||
| - [Bootstrap](https://getbootstrap.com/) as web UI framework | ||||
|  | ||||
| License | ||||
| ------- | ||||
| ## License | ||||
|  | ||||
| GPL 3.0 | ||||
|  | ||||
|   | ||||
							
								
								
									
										202
									
								
								docs/API.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								docs/API.md
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										22
									
								
								docs/Telegram.md
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										11
									
								
								frontend/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								frontend/Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| FROM golang:buster AS step_0 | ||||
| ENV CGO_ENABLED=0 GO111MODULE=on | ||||
| WORKDIR /root | ||||
| COPY . . | ||||
| RUN go build -ldflags "-w -s" -o /frontend | ||||
|  | ||||
| ################################################################################ | ||||
|  | ||||
| FROM scratch AS step_1 | ||||
| COPY --from=step_0 /frontend / | ||||
| ENTRYPOINT ["/frontend"] | ||||
| @@ -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"] | ||||
| @@ -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"] | ||||
| @@ -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"] | ||||
| @@ -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
									
								
							
							
						
						
									
										3
									
								
								frontend/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| .PHONY: all | ||||
| all: | ||||
| 	go build -ldflags "-w -s" -o frontend | ||||
							
								
								
									
										130
									
								
								frontend/api.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								frontend/api.go
									
									
									
									
									
										Normal 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) | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								frontend/assets/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								frontend/assets/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 32 KiB | 
							
								
								
									
										2
									
								
								frontend/assets/robots.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								frontend/assets/robots.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| User-agent: * | ||||
| Disallow: / | ||||
							
								
								
									
										7
									
								
								frontend/assets/static/jsdelivr/npm/bootstrap@4.5.1/dist/css/bootstrap.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								frontend/assets/static/jsdelivr/npm/bootstrap@4.5.1/dist/css/bootstrap.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										7
									
								
								frontend/assets/static/jsdelivr/npm/bootstrap@4.5.1/dist/js/bootstrap.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								frontend/assets/static/jsdelivr/npm/bootstrap@4.5.1/dist/js/bootstrap.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								frontend/assets/static/jsdelivr/npm/jquery@3.5.1/dist/jquery.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								frontend/assets/static/jsdelivr/npm/jquery@3.5.1/dist/jquery.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										8
									
								
								frontend/assets/static/jsdelivr/npm/viz.js@2.1.2/viz.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								frontend/assets/static/jsdelivr/npm/viz.js@2.1.2/viz.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										73
									
								
								frontend/assets/static/sortTable.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								frontend/assets/static/sortTable.js
									
									
									
									
									
										Normal 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); | ||||
|         }); | ||||
| } | ||||
							
								
								
									
										16
									
								
								frontend/assets/templates/bgpmap.tpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								frontend/assets/templates/bgpmap.tpl
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										2
									
								
								frontend/assets/templates/bird.tpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								frontend/assets/templates/bird.tpl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| <h2>{{ html .ServerName }}: {{ html .Target }}</h2> | ||||
| {{ .Result }} | ||||
							
								
								
									
										100
									
								
								frontend/assets/templates/page.tpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								frontend/assets/templates/page.tpl
									
									
									
									
									
										Normal 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 }}"> | ||||
| 				<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">»</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> | ||||
							
								
								
									
										21
									
								
								frontend/assets/templates/summary.tpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								frontend/assets/templates/summary.tpl
									
									
									
									
									
										Normal 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> | ||||
							
								
								
									
										2
									
								
								frontend/assets/templates/whois.tpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								frontend/assets/templates/whois.tpl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| <h2>whois {{ html .Target }}</h2> | ||||
| {{ .Result }} | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										100
									
								
								frontend/bgpmap_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								frontend/bgpmap_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func contains(s []string, str string) bool { | ||||
| 	for _, v := range s { | ||||
| 		if v == str { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func TestGetASNRepresentationDNS(t *testing.T) { | ||||
| 	checkNetwork(t) | ||||
|  | ||||
| 	setting.dnsInterface = "asn.cymru.com" | ||||
| 	setting.whoisServer = "" | ||||
| 	result := getASNRepresentation("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" | ||||
| 	result := getASNRepresentation("6939") | ||||
| 	if !strings.Contains(result, "HURRICANE") { | ||||
| 		t.Errorf("Lookup AS6939 failed, got %s", result) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestGetASNRepresentationFallback(t *testing.T) { | ||||
| 	setting.dnsInterface = "" | ||||
| 	setting.whoisServer = "" | ||||
| 	result := getASNRepresentation("6939") | ||||
| 	if result != "AS6939" { | ||||
| 		t.Errorf("Lookup AS6939 failed, got %s", result) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Broken due to random order of attributes | ||||
| func TestBirdRouteToGraphviz(t *testing.T) { | ||||
| 	setting.dnsInterface = "" | ||||
|  | ||||
| 	// Don't change formatting of the following strings! | ||||
|  | ||||
| 	fakeResult := `192.168.0.1/32       unicast [alpha 2021-01-14 from 192.168.0.2] * (100) [AS12345i] | ||||
| 	via 192.168.0.2 on eth0 | ||||
| 	Type: BGP univ | ||||
| 	BGP.origin: IGP | ||||
| 	BGP.as_path: 4242422601 | ||||
| 	BGP.next_hop: 172.18.0.2` | ||||
|  | ||||
| 	expectedLinesInResult := []string{ | ||||
| 		`"AS4242422601" [`, | ||||
| 		`"AS4242422601" -> "Target: 192.168.0.1" [`, | ||||
| 		`"Target: 192.168.0.1" [`, | ||||
| 		`"alpha" [`, | ||||
| 		`"alpha" -> "AS4242422601" [`, | ||||
| 	} | ||||
|  | ||||
| 	result := birdRouteToGraphviz([]string{ | ||||
| 		"alpha", | ||||
| 	}, []string{ | ||||
| 		fakeResult, | ||||
| 	}, "192.168.0.1") | ||||
|  | ||||
|  | ||||
| 	for _, line := range expectedLinesInResult { | ||||
| 		if !strings.Contains(result, line) { | ||||
| 			t.Errorf("Expected line in result not found: %s", line) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestBirdRouteToGraphvizXSS(t *testing.T) { | ||||
| 	setting.dnsInterface = "" | ||||
|  | ||||
| 	// Don't change formatting of the following strings! | ||||
|  | ||||
| 	fakeResult := `<script>alert("evil!")</script>` | ||||
|  | ||||
| 	result := birdRouteToGraphviz([]string{ | ||||
| 		"alpha", | ||||
| 	}, []string{ | ||||
| 		fakeResult, | ||||
| 	}, fakeResult) | ||||
|  | ||||
| 	if strings.Contains(result, "<script>") { | ||||
| 		t.Errorf("XSS injection succeeded: %s", result) | ||||
| 	} | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user