You've already forked bird-lg-go
mirror of
https://github.com/xddxdd/bird-lg-go
synced 2025-10-17 22:42:12 +02:00
Compare commits
87 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4a8c752157 | ||
![]() |
5ad6a4d35c | ||
![]() |
5422c8fd8c | ||
![]() |
5042980d79 | ||
![]() |
7884531a24 | ||
![]() |
cc804e81b6 | ||
![]() |
c9bab2ae2b | ||
![]() |
b9a4f95978 | ||
![]() |
7cd69746df | ||
![]() |
e719859d68 | ||
![]() |
5d06affefc | ||
![]() |
060fe9bf8e | ||
![]() |
f23d36f357 | ||
![]() |
1dbc0fccd2 | ||
![]() |
b2d64d19e3 | ||
![]() |
4dee4b0806 | ||
![]() |
cb279e0459 | ||
![]() |
31ba36beaf | ||
![]() |
5ab3b95d64 | ||
![]() |
7bf654f35f | ||
![]() |
5b33629a9d | ||
![]() |
0868c5d42c | ||
![]() |
bc61579e6a | ||
![]() |
e9750a8278 | ||
![]() |
d40dd3a4d3 | ||
![]() |
ffdeeac06e | ||
![]() |
7eb4d75bbf | ||
![]() |
6e5e190d32 | ||
![]() |
1b2573d87c | ||
![]() |
0d5337508b | ||
![]() |
b9094d3d6c | ||
![]() |
ec7f348418 | ||
![]() |
a632739443 | ||
![]() |
a9e278357a | ||
![]() |
e4c00c897f | ||
![]() |
4df3918b35 | ||
![]() |
45dc24470d | ||
![]() |
55ea5c3b28 | ||
![]() |
7eb44c3828 | ||
![]() |
124fdedbda | ||
![]() |
e6a98358b5 | ||
![]() |
761eb2160a | ||
![]() |
cc2a146a88 | ||
![]() |
3db9454350 | ||
![]() |
c30bed112c | ||
![]() |
af5ab3c78f | ||
![]() |
0fdde8afc7 | ||
![]() |
39a129db9d | ||
![]() |
0dd1c07b66 | ||
![]() |
f0f072c4a6 | ||
![]() |
657565857b | ||
![]() |
7ac2158e70 | ||
![]() |
5c433bc27a | ||
![]() |
1b0b923da9 | ||
![]() |
01438edaef | ||
![]() |
90f36610dc | ||
![]() |
6174208d07 | ||
![]() |
76174cdc08 | ||
![]() |
088bb6fe5a | ||
![]() |
3951eed011 | ||
![]() |
91c0a8962b | ||
![]() |
5f7850a903 | ||
![]() |
6a78cf2e80 | ||
![]() |
5b5a44bcb6 | ||
![]() |
ac31862237 | ||
![]() |
86129190ab | ||
![]() |
ff55064a20 | ||
![]() |
dbb02c04ed | ||
![]() |
c2b7de2e17 | ||
![]() |
c1b578e8db | ||
![]() |
7b0e5689d4 | ||
![]() |
3c46bda49d | ||
![]() |
32e00d2ce3 | ||
![]() |
a19750cdef | ||
![]() |
7f1cdaa4ee | ||
![]() |
2d2193041e | ||
![]() |
aad8ee98d7 | ||
![]() |
00b5c12787 | ||
![]() |
55a1eb54fd | ||
![]() |
0594edc69d | ||
![]() |
38bf6aba09 | ||
![]() |
d261c22235 | ||
![]() |
19aa8c77c5 | ||
![]() |
fe07ebb5a5 | ||
![]() |
66547ebfa9 | ||
![]() |
d253e4311b | ||
![]() |
026498ba2f |
16
.github/workflows/auto-merge.yml
vendored
Normal file
16
.github/workflows/auto-merge.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
name: auto-merge
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
|
||||
jobs:
|
||||
auto-merge:
|
||||
name: Dependabot Auto Merge
|
||||
runs-on: ubuntu-latest
|
||||
if: github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ahmadnassri/action-dependabot-auto-merge@v2
|
||||
with:
|
||||
target: minor
|
||||
github-token: ${{ secrets.AUTOMERGE_TOKEN }}
|
21
.github/workflows/develop.yaml
vendored
21
.github/workflows/develop.yaml
vendored
@@ -47,7 +47,7 @@ jobs:
|
||||
- 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 -I 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
|
||||
|
||||
@@ -57,6 +57,12 @@ jobs:
|
||||
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
|
||||
|
||||
- name: Test mtr binary in proxy image
|
||||
run: |
|
||||
docker build -t local/proxy:mtr -f proxy/Dockerfile.mtr proxy/
|
||||
docker run --rm --net host --entrypoint mtr local/proxy:mtr -w -c1 -Z1 -G1 -b 127.0.0.1 || exit 1
|
||||
docker run --rm --net host --entrypoint mtr local/proxy:mtr -w -c1 -Z1 -G1 -b ::1 || exit 1
|
||||
|
||||
docker-develop:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
@@ -106,3 +112,16 @@ jobs:
|
||||
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 }}
|
||||
|
||||
- name: Build proxy docker image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: '{{defaultContext}}:proxy'
|
||||
file: 'Dockerfile.mtr'
|
||||
platforms: linux/amd64,linux/arm64,linux/386,linux/arm/v7
|
||||
push: true
|
||||
tags: |
|
||||
xddxdd/bird-lgproxy-go:develop-mtr
|
||||
xddxdd/bird-lgproxy-go:develop-${{ github.sha }}-mtr
|
||||
ghcr.io/xddxdd/bird-lg-go:proxy-develop-mtr
|
||||
ghcr.io/xddxdd/bird-lg-go:proxy-develop-${{ github.sha }}-mtr
|
||||
|
13
.github/workflows/release.yaml
vendored
13
.github/workflows/release.yaml
vendored
@@ -85,3 +85,16 @@ jobs:
|
||||
xddxdd/bird-lgproxy-go:${{ github.event.release.tag_name }}
|
||||
ghcr.io/xddxdd/bird-lg-go:proxy
|
||||
ghcr.io/xddxdd/bird-lg-go:proxy-${{ github.event.release.tag_name }}
|
||||
|
||||
- name: Build proxy docker image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: '{{defaultContext}}:proxy'
|
||||
file: 'Dockerfile.mtr'
|
||||
platforms: linux/amd64,linux/arm64,linux/386,linux/arm/v7
|
||||
push: true
|
||||
tags: |
|
||||
xddxdd/bird-lgproxy-go:latest-mtr
|
||||
xddxdd/bird-lgproxy-go:${{ github.event.release.tag_name }}-mtr
|
||||
ghcr.io/xddxdd/bird-lg-go:proxy-mtr
|
||||
ghcr.io/xddxdd/bird-lg-go:proxy-${{ github.event.release.tag_name }}-mtr
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@@ -20,7 +20,3 @@ proxy/proxy
|
||||
|
||||
# don't include generated bindata file
|
||||
frontend/bindata.go
|
||||
|
||||
# don't include generated Dockerfiles
|
||||
frontend/Dockerfile.*
|
||||
proxy/Dockerfile.*
|
@@ -167,6 +167,7 @@ Example: the following docker-compose.yml entry does the same as above, but by s
|
||||
services:
|
||||
bird-lgproxy:
|
||||
# Use xddxdd/bird-lgproxy-go:develop for the latest build from master branch
|
||||
# Use xddxdd/bird-lgproxy-go:latest-mtr to use MTR instead of Traceroute
|
||||
image: xddxdd/bird-lgproxy-go:latest
|
||||
container_name: bird-lgproxy
|
||||
restart: always
|
||||
|
@@ -20,6 +20,7 @@ type apiGenericResultPair struct {
|
||||
type apiSummaryResultPair struct {
|
||||
Server string `json:"server"`
|
||||
Data []SummaryRowData `json:"data"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type apiResponse struct {
|
||||
@@ -70,9 +71,12 @@ func apiSummaryHandler(request apiRequest) 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: []SummaryRowData{},
|
||||
Error: err.Error(),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
response.Result = append(response.Result, &apiSummaryResultPair{
|
||||
|
@@ -73,13 +73,14 @@ func TestApiSummaryHandler(t *testing.T) {
|
||||
|
||||
summary := response.Result[0].(*apiSummaryResultPair)
|
||||
assert.Equal(t, summary.Server, "alpha")
|
||||
assert.Equal(t, len(summary.Data), 7)
|
||||
// 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, "")
|
||||
assert.Equal(t, summary.Data[0].Name, "device1")
|
||||
assert.Equal(t, summary.Data[0].Proto, "Device")
|
||||
assert.Equal(t, summary.Data[0].Table, "---")
|
||||
assert.Equal(t, summary.Data[0].State, "up")
|
||||
assert.Equal(t, summary.Data[0].Since, "2021-08-27")
|
||||
assert.Equal(t, summary.Data[0].Info, "")
|
||||
}
|
||||
|
||||
func TestApiSummaryHandlerError(t *testing.T) {
|
||||
@@ -100,7 +101,10 @@ func TestApiSummaryHandlerError(t *testing.T) {
|
||||
}
|
||||
response := apiSummaryHandler(request)
|
||||
|
||||
assert.Equal(t, response.Error, "Mock backend error")
|
||||
assert.Equal(t, response.Error, "")
|
||||
|
||||
summary := response.Result[0].(*apiSummaryResultPair)
|
||||
assert.Equal(t, summary.Error, "Mock backend error")
|
||||
}
|
||||
|
||||
func TestApiWhoisHandler(t *testing.T) {
|
||||
|
@@ -5,8 +5,19 @@
|
||||
<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>
|
||||
function decodeBase64(base64) {
|
||||
const text = atob(base64);
|
||||
const length = text.length;
|
||||
const bytes = new Uint8Array(length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
bytes[i] = text.charCodeAt(i);
|
||||
}
|
||||
const decoder = new TextDecoder();
|
||||
return decoder.decode(bytes);
|
||||
}
|
||||
|
||||
var viz = new Viz();
|
||||
viz.renderSVGElement(atob({{ .Result }}))
|
||||
viz.renderSVGElement(decodeBase64({{ .Result }}))
|
||||
.then(element => {
|
||||
document.getElementById("bgpmap").appendChild(element);
|
||||
})
|
||||
|
@@ -7,7 +7,20 @@
|
||||
<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">
|
||||
<link rel="stylesheet" href="/static/jsdelivr/npm/bootstrap@4.5.1/dist/css/bootstrap.min.css" crossorigin="anonymous">
|
||||
<style>
|
||||
.navbar-nav {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.navbar form {
|
||||
min-width: 400px;
|
||||
}
|
||||
.nav-link {
|
||||
padding: 0.2rem 0.5rem !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
</head>
|
||||
<body>
|
||||
@@ -74,8 +87,8 @@
|
||||
{{ .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/jsdelivr/npm/jquery@3.5.1/dist/jquery.min.js" crossorigin="anonymous"></script>
|
||||
<script src="/static/jsdelivr/npm/bootstrap@4.5.1/dist/js/bootstrap.min.js" crossorigin="anonymous"></script>
|
||||
<script src="/static/sortTable.js"></script>
|
||||
|
||||
<script>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
@@ -69,11 +70,15 @@ func (graph *RouteGraph) attrsToString(attrs RouteAttrs) string {
|
||||
}
|
||||
|
||||
func (graph *RouteGraph) escape(s string) string {
|
||||
result, err := json.Marshal(s)
|
||||
buffer := &bytes.Buffer{}
|
||||
encoder := json.NewEncoder(buffer)
|
||||
encoder.SetEscapeHTML(false)
|
||||
err := encoder.Encode(s)
|
||||
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
} else {
|
||||
return string(result)
|
||||
return string(buffer.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -33,7 +33,7 @@ func TestBirdRouteToGraphvizXSS(t *testing.T) {
|
||||
fakeResult,
|
||||
}, fakeResult)
|
||||
|
||||
if strings.Contains(result, "<script>") {
|
||||
if strings.Contains(result, fakeResult) {
|
||||
t.Errorf("XSS injection succeeded: %s", result)
|
||||
}
|
||||
}
|
||||
|
@@ -1,33 +1,27 @@
|
||||
module github.com/xddxdd/bird-lg-go/frontend
|
||||
|
||||
go 1.17
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/gorilla/handlers v1.5.1
|
||||
github.com/jarcoal/httpmock v1.3.1
|
||||
github.com/magiconair/properties v1.8.7
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.17.0
|
||||
github.com/gorilla/handlers v1.5.2
|
||||
github.com/jarcoal/httpmock v1.4.1
|
||||
github.com/magiconair/properties v1.8.10
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/spf13/viper v1.21.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.3.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.10.0 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
||||
github.com/spf13/afero v1.15.0 // indirect
|
||||
github.com/spf13/cast v1.10.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/sys v0.12.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
)
|
||||
|
2104
frontend/go.sum
2104
frontend/go.sum
File diff suppressed because it is too large
Load Diff
@@ -2,11 +2,14 @@ package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jarcoal/httpmock"
|
||||
)
|
||||
|
||||
type channelData struct {
|
||||
@@ -14,6 +17,29 @@ type channelData struct {
|
||||
data string
|
||||
}
|
||||
|
||||
func createConnectionTimeoutRoundTripper(timeout int) http.RoundTripper {
|
||||
context := net.Dialer{
|
||||
Timeout: time.Duration(timeout) * time.Second,
|
||||
}
|
||||
|
||||
// Prefer httpmock's transport if activated, so unit tests can work
|
||||
if http.DefaultTransport == httpmock.DefaultTransport {
|
||||
return httpmock.DefaultTransport
|
||||
}
|
||||
|
||||
return &http.Transport{
|
||||
DialContext: context.DialContext,
|
||||
|
||||
// Default options from transport.go
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
ForceAttemptHTTP2: true,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
}
|
||||
}
|
||||
|
||||
// Send commands to lgproxy instances in parallel, and retrieve their responses
|
||||
func batchRequest(servers []string, endpoint string, command string) []string {
|
||||
// Channel and array for storing responses
|
||||
@@ -47,7 +73,10 @@ func batchRequest(servers []string, endpoint string, command string) []string {
|
||||
}
|
||||
url := "http://" + hostname + ":" + strconv.Itoa(setting.proxyPort) + "/" + url.PathEscape(endpoint) + "?q=" + url.QueryEscape(command)
|
||||
go func(url string, i int) {
|
||||
client := http.Client{Timeout: time.Duration(setting.timeOut) * time.Second}
|
||||
client := http.Client{
|
||||
Transport: createConnectionTimeoutRoundTripper(setting.connectionTimeOut),
|
||||
Timeout: time.Duration(setting.timeOut) * time.Second,
|
||||
}
|
||||
response, err := client.Get(url)
|
||||
if err != nil {
|
||||
ch <- channelData{i, "request failed: " + err.Error() + "\n"}
|
||||
|
@@ -7,24 +7,26 @@ import (
|
||||
)
|
||||
|
||||
type settingType struct {
|
||||
servers []string
|
||||
serversDisplay []string
|
||||
domain string
|
||||
proxyPort int
|
||||
whoisServer string
|
||||
listen string
|
||||
dnsInterface string
|
||||
netSpecificMode string
|
||||
titleBrand string
|
||||
navBarBrand string
|
||||
navBarBrandURL string
|
||||
navBarAllServer string
|
||||
navBarAllURL string
|
||||
bgpmapInfo string
|
||||
telegramBotName string
|
||||
protocolFilter []string
|
||||
nameFilter string
|
||||
timeOut int
|
||||
servers []string
|
||||
serversDisplay []string
|
||||
domain string
|
||||
proxyPort int
|
||||
whoisServer string
|
||||
listen []string
|
||||
dnsInterface string
|
||||
netSpecificMode string
|
||||
titleBrand string
|
||||
navBarBrand string
|
||||
navBarBrandURL string
|
||||
navBarAllServer string
|
||||
navBarAllURL string
|
||||
bgpmapInfo string
|
||||
telegramBotName string
|
||||
protocolFilter []string
|
||||
nameFilter string
|
||||
timeOut int
|
||||
connectionTimeOut int
|
||||
trustProxyHeaders bool
|
||||
}
|
||||
|
||||
var setting settingType
|
||||
@@ -33,24 +35,29 @@ func main() {
|
||||
parseSettings()
|
||||
ImportTemplates()
|
||||
|
||||
var l net.Listener
|
||||
var err error
|
||||
for _, listenAddr := range setting.listen {
|
||||
go func(listenAddr string) {
|
||||
var l net.Listener
|
||||
var err error
|
||||
|
||||
if strings.HasPrefix(setting.listen, "/") {
|
||||
// Delete existing socket file, ignore errors (will fail later anyway)
|
||||
os.Remove(setting.listen)
|
||||
l, err = net.Listen("unix", setting.listen)
|
||||
} else {
|
||||
listenAddr := setting.listen
|
||||
if !strings.Contains(listenAddr, ":") {
|
||||
listenAddr = ":" + listenAddr
|
||||
}
|
||||
l, err = net.Listen("tcp", listenAddr)
|
||||
if strings.HasPrefix(listenAddr, "/") {
|
||||
// Delete existing socket file, ignore errors (will fail later anyway)
|
||||
os.Remove(listenAddr)
|
||||
l, err = net.Listen("unix", listenAddr)
|
||||
} else {
|
||||
if !strings.Contains(listenAddr, ":") {
|
||||
listenAddr = ":" + listenAddr
|
||||
}
|
||||
l, err = net.Listen("tcp", listenAddr)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
webServerStart(l)
|
||||
}(listenAddr)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
webServerStart(l)
|
||||
select {}
|
||||
}
|
||||
|
@@ -35,15 +35,6 @@ var optionsMap = map[string]string{
|
||||
"traceroute": "traceroute ...",
|
||||
}
|
||||
|
||||
// pre-compiled regexp and constant statemap for summary rendering
|
||||
var splitSummaryLine = regexp.MustCompile(`(\w+)(\s+)(\w+)(\s+)([\w-]+)(\s+)(\w+)(\s+)([0-9\-\. :]+)(.*)`)
|
||||
var summaryStateMap = map[string]string{
|
||||
"up": "success",
|
||||
"down": "secondary",
|
||||
"start": "danger",
|
||||
"passive": "info",
|
||||
}
|
||||
|
||||
// render the page template
|
||||
func renderPageTemplate(w http.ResponseWriter, r *http.Request, title string, content template.HTML) {
|
||||
path := r.URL.Path[1:]
|
||||
@@ -143,58 +134,23 @@ func summaryParse(data string, serverName string) (TemplateSummary, error) {
|
||||
|
||||
// parse each line
|
||||
for _, line := range rows {
|
||||
|
||||
// Ignore empty lines
|
||||
line = strings.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
row := SummaryRowDataFromLine(line)
|
||||
if row == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse a total of 6 columns from bird summary
|
||||
lineSplitted := splitSummaryLine.FindStringSubmatch(line)
|
||||
if lineSplitted == nil {
|
||||
// Filter row name
|
||||
if setting.nameFilter != "" && nameFilterRegexp.MatchString(row.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
var row SummaryRowData
|
||||
|
||||
if len(lineSplitted) >= 2 {
|
||||
row.Name = strings.TrimSpace(lineSplitted[1])
|
||||
if setting.nameFilter != "" && nameFilterRegexp.MatchString(row.Name) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(lineSplitted) >= 4 {
|
||||
row.Proto = strings.TrimSpace(lineSplitted[3])
|
||||
// Filter away unwanted protocol types, if setting.protocolFilter is non-empty
|
||||
found := false
|
||||
for _, protocol := range setting.protocolFilter {
|
||||
if strings.EqualFold(row.Proto, protocol) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(setting.protocolFilter) > 0 && !found {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(lineSplitted) >= 6 {
|
||||
row.Table = strings.TrimSpace(lineSplitted[5])
|
||||
}
|
||||
if len(lineSplitted) >= 8 {
|
||||
row.State = strings.TrimSpace(lineSplitted[7])
|
||||
row.MappedState = summaryStateMap[row.State]
|
||||
}
|
||||
if len(lineSplitted) >= 10 {
|
||||
row.Since = strings.TrimSpace(lineSplitted[9])
|
||||
}
|
||||
if len(lineSplitted) >= 11 {
|
||||
row.Info = strings.TrimSpace(lineSplitted[10])
|
||||
// Filter away unwanted protocol types, if setting.protocolFilter is non-empty
|
||||
if len(setting.protocolFilter) > 0 && !row.ProtocolMatches(setting.protocolFilter) {
|
||||
continue
|
||||
}
|
||||
|
||||
// add to the result
|
||||
args.Rows = append(args.Rows, row)
|
||||
args.Rows = append(args.Rows, *row)
|
||||
}
|
||||
|
||||
return args, nil
|
||||
|
@@ -8,8 +8,7 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
const BirdSummaryData = `BIRD 2.0.8 ready.
|
||||
Name Proto Table State Since Info
|
||||
const BirdSummaryData = `Name Proto Table State Since Info
|
||||
static1 Static master4 up 2021-08-27
|
||||
static2 Static master6 up 2021-08-27
|
||||
device1 Device --- up 2021-08-27
|
||||
|
@@ -9,23 +9,25 @@ import (
|
||||
)
|
||||
|
||||
type viperSettingType struct {
|
||||
Servers string `mapstructure:"servers"`
|
||||
Domain string `mapstructure:"domain"`
|
||||
ProxyPort int `mapstructure:"proxy_port"`
|
||||
WhoisServer string `mapstructure:"whois"`
|
||||
Listen string `mapstructure:"listen"`
|
||||
DNSInterface string `mapstructure:"dns_interface"`
|
||||
NetSpecificMode string `mapstructure:"net_specific_mode"`
|
||||
TitleBrand string `mapstructure:"title_brand"`
|
||||
NavBarBrand string `mapstructure:"navbar_brand"`
|
||||
NavBarBrandURL string `mapstructure:"navbar_brand_url"`
|
||||
NavBarAllServer string `mapstructure:"navbar_all_servers"`
|
||||
NavBarAllURL string `mapstructure:"navbar_all_url"`
|
||||
BgpmapInfo string `mapstructure:"bgpmap_info"`
|
||||
TelegramBotName string `mapstructure:"telegram_bot_name"`
|
||||
ProtocolFilter string `mapstructure:"protocol_filter"`
|
||||
NameFilter string `mapstructure:"name_filter"`
|
||||
TimeOut int `mapstructure:"timeout"`
|
||||
Servers string `mapstructure:"servers"`
|
||||
Domain string `mapstructure:"domain"`
|
||||
ProxyPort int `mapstructure:"proxy_port"`
|
||||
WhoisServer string `mapstructure:"whois"`
|
||||
Listen []string `mapstructure:"listen"`
|
||||
DNSInterface string `mapstructure:"dns_interface"`
|
||||
NetSpecificMode string `mapstructure:"net_specific_mode"`
|
||||
TitleBrand string `mapstructure:"title_brand"`
|
||||
NavBarBrand string `mapstructure:"navbar_brand"`
|
||||
NavBarBrandURL string `mapstructure:"navbar_brand_url"`
|
||||
NavBarAllServer string `mapstructure:"navbar_all_servers"`
|
||||
NavBarAllURL string `mapstructure:"navbar_all_url"`
|
||||
BgpmapInfo string `mapstructure:"bgpmap_info"`
|
||||
TelegramBotName string `mapstructure:"telegram_bot_name"`
|
||||
ProtocolFilter string `mapstructure:"protocol_filter"`
|
||||
NameFilter string `mapstructure:"name_filter"`
|
||||
TimeOut int `mapstructure:"timeout"`
|
||||
ConnectionTimeOut int `mapstructure:"connection_timeout"`
|
||||
TrustProxyHeaders bool `mapstructure:"trust_proxy_headers"`
|
||||
}
|
||||
|
||||
// Parse settings with viper, and convert to legacy setting format
|
||||
@@ -50,7 +52,7 @@ func parseSettings() {
|
||||
pflag.String("whois", "whois.verisign-grs.com", "whois server for queries")
|
||||
viper.BindPFlag("whois", pflag.Lookup("whois"))
|
||||
|
||||
pflag.String("listen", "5000", "address or unix socket bird-lg is listening on")
|
||||
pflag.StringSlice("listen", []string{"5000"}, "address or unix socket bird-lg is listening on")
|
||||
viper.BindPFlag("listen", pflag.Lookup("listen"))
|
||||
|
||||
pflag.String("dns-interface", "asn.cymru.com", "dns zone to query ASN information")
|
||||
@@ -87,9 +89,15 @@ func parseSettings() {
|
||||
pflag.String("name-filter", "", "protocol name regex to hide in summary tables (RE2 syntax); defaults to none if not set")
|
||||
viper.BindPFlag("name_filter", pflag.Lookup("name-filter"))
|
||||
|
||||
pflag.Int("time-out", 120, "time before request timed out, in seconds; defaults to 120 if not set")
|
||||
pflag.Int("time-out", 120, "time before backend HTTP request times out, in seconds; defaults to 120 if not set")
|
||||
viper.BindPFlag("timeout", pflag.Lookup("time-out"))
|
||||
|
||||
pflag.Int("connection-time-out", 5, "time before backend TCP connection times out, in seconds; defaults to 5 if not set")
|
||||
viper.BindPFlag("connection_timeout", pflag.Lookup("connection-time-out"))
|
||||
|
||||
pflag.Bool("trust-proxy-headers", false, "Trust X-Forwared-For, X-Real-IP, X-Forwarded-Proto, X-Forwarded-Scheme and X-Forwarded-Host sent by the client")
|
||||
viper.BindPFlag("trust_proxy_headers", pflag.Lookup("trust-proxy-headers"))
|
||||
|
||||
pflag.Parse()
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
@@ -139,6 +147,8 @@ func parseSettings() {
|
||||
|
||||
setting.nameFilter = viperSettings.NameFilter
|
||||
setting.timeOut = viperSettings.TimeOut
|
||||
setting.connectionTimeOut = viperSettings.ConnectionTimeOut
|
||||
setting.trustProxyHeaders = viperSettings.TrustProxyHeaders
|
||||
|
||||
fmt.Printf("%#v\n", setting)
|
||||
}
|
||||
|
@@ -3,11 +3,13 @@ package main
|
||||
import (
|
||||
"embed"
|
||||
"html/template"
|
||||
"net/url"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// import templates and other assets
|
||||
//
|
||||
//go:embed assets
|
||||
var assets embed.FS
|
||||
|
||||
@@ -64,6 +66,47 @@ func (r SummaryRowData) NameContains(prefix string) bool {
|
||||
return strings.Contains(r.Name, prefix)
|
||||
}
|
||||
|
||||
func (r SummaryRowData) ProtocolMatches(protocols []string) bool {
|
||||
for _, protocol := range protocols {
|
||||
if strings.EqualFold(r.Proto, protocol) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// pre-compiled regexp and constant statemap for summary rendering
|
||||
var splitSummaryLine = regexp.MustCompile(`^([\w-]+)\s+(\w+)\s+([\w-]+)\s+(\w+)\s+([0-9\-\. :]+)(.*)$`)
|
||||
var summaryStateMap = map[string]string{
|
||||
"up": "success",
|
||||
"down": "secondary",
|
||||
"start": "danger",
|
||||
"passive": "info",
|
||||
}
|
||||
|
||||
func SummaryRowDataFromLine(line string) *SummaryRowData {
|
||||
lineSplitted := splitSummaryLine.FindStringSubmatch(line)
|
||||
if lineSplitted == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var row SummaryRowData
|
||||
row.Name = strings.TrimSpace(lineSplitted[1])
|
||||
row.Proto = strings.TrimSpace(lineSplitted[2])
|
||||
row.Table = strings.TrimSpace(lineSplitted[3])
|
||||
row.State = strings.TrimSpace(lineSplitted[4])
|
||||
row.Since = strings.TrimSpace(lineSplitted[5])
|
||||
row.Info = strings.TrimSpace(lineSplitted[6])
|
||||
|
||||
if strings.Contains(row.Info, "Passive") {
|
||||
row.MappedState = summaryStateMap["passive"]
|
||||
} else {
|
||||
row.MappedState = summaryStateMap[row.State]
|
||||
}
|
||||
|
||||
return &row
|
||||
}
|
||||
|
||||
type TemplateSummary struct {
|
||||
ServerName string
|
||||
Raw string
|
||||
@@ -108,7 +151,7 @@ var requiredTemplates = [...]string{
|
||||
// define functions to be made available in templates
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
"pathescape": url.PathEscape,
|
||||
"pathescape": url.PathEscape,
|
||||
}
|
||||
|
||||
// import templates from embedded assets
|
||||
|
@@ -23,3 +23,67 @@ func TestSummaryRowDataNameContains(t *testing.T) {
|
||||
assert.Equal(t, data.NameContains("oc"), true)
|
||||
assert.Equal(t, data.NameContains("no"), false)
|
||||
}
|
||||
|
||||
func TestSummaryRowDataFromLine(t *testing.T) {
|
||||
data := SummaryRowDataFromLine("sys_device Device --- up 2025-06-27 21:23:08")
|
||||
|
||||
assert.Equal(t, data.Name, "sys_device")
|
||||
assert.Equal(t, data.Proto, "Device")
|
||||
assert.Equal(t, data.Table, "---")
|
||||
assert.Equal(t, data.State, "up")
|
||||
assert.Equal(t, data.Since, "2025-06-27 21:23:08")
|
||||
}
|
||||
|
||||
func TestSummaryRowDataFromLineNumeric(t *testing.T) {
|
||||
data := SummaryRowDataFromLine("12345 Device --- up 2025-06-27 21:23:08")
|
||||
|
||||
assert.Equal(t, data.Name, "12345")
|
||||
assert.Equal(t, data.Proto, "Device")
|
||||
assert.Equal(t, data.Table, "---")
|
||||
assert.Equal(t, data.State, "up")
|
||||
assert.Equal(t, data.Since, "2025-06-27 21:23:08")
|
||||
}
|
||||
|
||||
func TestSummaryRowDataFromLinePipe(t *testing.T) {
|
||||
data := SummaryRowDataFromLine("pipe Pipe --- up 2025-06-27 21:23:08 master4 <=> pipe_v4")
|
||||
|
||||
assert.Equal(t, data.Name, "pipe")
|
||||
assert.Equal(t, data.Proto, "Pipe")
|
||||
assert.Equal(t, data.Table, "---")
|
||||
assert.Equal(t, data.State, "up")
|
||||
assert.Equal(t, data.Since, "2025-06-27 21:23:08")
|
||||
assert.Equal(t, data.Info, "master4 <=> pipe_v4")
|
||||
}
|
||||
|
||||
func TestSummaryRowDataFromLineBGP(t *testing.T) {
|
||||
data := SummaryRowDataFromLine("bgp BGP --- up 2025-06-30 20:45:33 Established")
|
||||
|
||||
assert.Equal(t, data.Name, "bgp")
|
||||
assert.Equal(t, data.Proto, "BGP")
|
||||
assert.Equal(t, data.Table, "---")
|
||||
assert.Equal(t, data.State, "up")
|
||||
assert.Equal(t, data.Since, "2025-06-30 20:45:33")
|
||||
assert.Equal(t, data.Info, "Established")
|
||||
}
|
||||
|
||||
func TestSummaryRowDataFromLineBGPPassive(t *testing.T) {
|
||||
data := SummaryRowDataFromLine("passive BGP --- start 2025-06-27 21:23:08 Passive")
|
||||
|
||||
assert.Equal(t, data.Name, "passive")
|
||||
assert.Equal(t, data.Proto, "BGP")
|
||||
assert.Equal(t, data.Table, "---")
|
||||
assert.Equal(t, data.State, "start")
|
||||
assert.Equal(t, data.Since, "2025-06-27 21:23:08")
|
||||
assert.Equal(t, data.Info, "Passive")
|
||||
}
|
||||
|
||||
func TestSummaryRowDataFromLineWithDash(t *testing.T) {
|
||||
data := SummaryRowDataFromLine("ibgp_test-01 BGP --- up 07:16:51.656 Established")
|
||||
|
||||
assert.Equal(t, data.Name, "ibgp_test-01")
|
||||
assert.Equal(t, data.Proto, "BGP")
|
||||
assert.Equal(t, data.Table, "---")
|
||||
assert.Equal(t, data.State, "up")
|
||||
assert.Equal(t, data.Since, "07:16:51.656")
|
||||
assert.Equal(t, data.Info, "Established")
|
||||
}
|
||||
|
@@ -12,19 +12,20 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/gorilla/handlers"
|
||||
)
|
||||
|
||||
var primitiveMap = map[string]string{
|
||||
"summary": "show protocols",
|
||||
"detail": "show protocols all %s",
|
||||
"route_from_protocol": "show route protocol %s",
|
||||
"route_from_protocol_all": "show route protocol %s all",
|
||||
"route_from_protocol_primary": "show route protocol %s primary",
|
||||
"route_from_protocol_all_primary": "show route protocol %s all primary",
|
||||
"route_filtered_from_protocol": "show route filtered protocol %s",
|
||||
"route_filtered_from_protocol_all": "show route filtered protocol %s all",
|
||||
"detail": "show protocols all \"%s\"",
|
||||
"route_from_protocol": "show route protocol \"%s\"",
|
||||
"route_from_protocol_all": "show route protocol \"%s\" all",
|
||||
"route_from_protocol_primary": "show route protocol \"%s\" primary",
|
||||
"route_from_protocol_all_primary": "show route protocol \"%s\" all primary",
|
||||
"route_filtered_from_protocol": "show route filtered protocol \"%s\"",
|
||||
"route_filtered_from_protocol_all": "show route filtered protocol \"%s\" all",
|
||||
"route_from_origin": "show route where bgp_path.last = %s",
|
||||
"route_from_origin_all": "show route where bgp_path.last = %s all",
|
||||
"route_from_origin_primary": "show route where bgp_path.last = %s primary",
|
||||
@@ -39,8 +40,10 @@ var primitiveMap = map[string]string{
|
||||
"traceroute": "%s",
|
||||
}
|
||||
|
||||
var webServerPrepared uint32 = 0
|
||||
|
||||
// serve up a generic error
|
||||
func serverError(w http.ResponseWriter, r *http.Request) {
|
||||
func serverError(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte("500 Internal Server Error"))
|
||||
}
|
||||
@@ -75,7 +78,6 @@ func webHandlerWhois(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// serve up results from bird
|
||||
func webBackendCommunicator(endpoint string, command string) func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
backendCommandPrimitive, commandPresent := primitiveMap[command]
|
||||
if !commandPresent {
|
||||
panic("invalid command: " + command)
|
||||
@@ -193,12 +195,11 @@ func webHandlerBGPMap(endpoint string, command string) func(w http.ResponseWrite
|
||||
}
|
||||
}
|
||||
|
||||
// set up routing paths and start webserver
|
||||
func webServerStart(l net.Listener) {
|
||||
|
||||
// set up routing paths
|
||||
func webServerPrepare() {
|
||||
// redirect main page to all server summary
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/summary/"+url.PathEscape(strings.Join(setting.servers, "+")), 302)
|
||||
http.Redirect(w, r, "/summary/"+url.PathEscape(strings.Join(setting.servers, "+")), http.StatusFound)
|
||||
})
|
||||
|
||||
// serve static pages using embedded assets from template.go
|
||||
@@ -237,7 +238,19 @@ func webServerStart(l net.Listener) {
|
||||
http.HandleFunc("/whois/", webHandlerWhois)
|
||||
http.HandleFunc("/api/", apiHandler)
|
||||
http.HandleFunc("/telegram/", webHandlerTelegramBot)
|
||||
|
||||
// Start HTTP server
|
||||
http.Serve(l, handlers.LoggingHandler(os.Stdout, http.DefaultServeMux))
|
||||
}
|
||||
|
||||
// start webserver
|
||||
func webServerStart(l net.Listener) {
|
||||
if atomic.SwapUint32(&webServerPrepared, 1) == 0 {
|
||||
webServerPrepare()
|
||||
}
|
||||
|
||||
var handler http.Handler
|
||||
handler = http.DefaultServeMux
|
||||
if setting.trustProxyHeaders {
|
||||
handler = handlers.ProxyHeaders(handler)
|
||||
}
|
||||
handler = handlers.LoggingHandler(os.Stdout, handler)
|
||||
http.Serve(l, handler)
|
||||
}
|
||||
|
@@ -88,7 +88,7 @@ func TestWhoisWithoutServer(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWhoisConnectionError(t *testing.T) {
|
||||
setting.whoisServer = "127.0.0.1:0"
|
||||
setting.whoisServer = "127.0.0.1:1"
|
||||
result := whois("AS6939")
|
||||
if !strings.Contains(result, "connect: connection refused") {
|
||||
t.Errorf("Whois AS6939 without server produced output, got %s", result)
|
||||
|
31
proxy/Dockerfile.mtr
Normal file
31
proxy/Dockerfile.mtr
Normal file
@@ -0,0 +1,31 @@
|
||||
FROM golang AS step_0
|
||||
|
||||
ENV CGO_ENABLED=0 GO111MODULE=on
|
||||
WORKDIR /root
|
||||
COPY . .
|
||||
RUN go build -ldflags "-w -s" -o /proxy
|
||||
|
||||
################################################################################
|
||||
|
||||
FROM alpine:edge AS step_1
|
||||
|
||||
WORKDIR /root
|
||||
RUN apk add --no-cache build-base linux-headers
|
||||
|
||||
RUN wget https://www.bitwizard.nl/mtr/files/mtr-0.94.tar.gz \
|
||||
-O mtr-0.94.tar.gz
|
||||
RUN tar xvf mtr-0.94.tar.gz \
|
||||
&& cd mtr-0.94 \
|
||||
&& ./configure --without-gtk --without-ncurses --without-jansson --without-ipinfo --disable-bash-completion \
|
||||
&& make -j4 LDFLAGS="-static" \
|
||||
&& strip /root/mtr-0.94/mtr \
|
||||
&& strip /root/mtr-0.94/mtr-packet
|
||||
|
||||
################################################################################
|
||||
|
||||
FROM scratch AS step_2
|
||||
ENV PATH=/
|
||||
COPY --from=step_0 /proxy /
|
||||
COPY --from=step_1 /root/mtr-0.94/mtr /
|
||||
COPY --from=step_1 /root/mtr-0.94/mtr-packet /
|
||||
ENTRYPOINT ["/proxy"]
|
38
proxy/go.mod
38
proxy/go.mod
@@ -1,32 +1,26 @@
|
||||
module github.com/xddxdd/bird-lg-go/proxy
|
||||
|
||||
go 1.17
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/gorilla/handlers v1.5.1
|
||||
github.com/magiconair/properties v1.8.7
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.17.0
|
||||
github.com/gorilla/handlers v1.5.2
|
||||
github.com/magiconair/properties v1.8.10
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/spf13/viper v1.21.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/felixge/httpsnoop v1.0.3 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.3.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.10.0 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
||||
github.com/spf13/afero v1.15.0 // indirect
|
||||
github.com/spf13/cast v1.10.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/sys v0.12.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
)
|
||||
|
2096
proxy/go.sum
2096
proxy/go.sum
File diff suppressed because it is too large
Load Diff
@@ -62,7 +62,7 @@ func accessHandler(next http.Handler) http.Handler {
|
||||
|
||||
type settingType struct {
|
||||
birdSocket string
|
||||
listen string
|
||||
listen []string
|
||||
allowedNets []*net.IPNet
|
||||
tr_bin string
|
||||
tr_flags []string
|
||||
@@ -76,32 +76,40 @@ func main() {
|
||||
parseSettings()
|
||||
tracerouteAutodetect()
|
||||
|
||||
fmt.Printf("Listening on %s...\n", setting.listen)
|
||||
mux := http.NewServeMux()
|
||||
|
||||
var l net.Listener
|
||||
var err error
|
||||
// Prepare HTTP server
|
||||
mux.HandleFunc("/", invalidHandler)
|
||||
mux.HandleFunc("/bird", birdHandler)
|
||||
mux.HandleFunc("/bird6", birdHandler)
|
||||
mux.HandleFunc("/traceroute", tracerouteHandler)
|
||||
mux.HandleFunc("/traceroute6", tracerouteHandler)
|
||||
|
||||
if strings.HasPrefix(setting.listen, "/") {
|
||||
// Delete existing socket file, ignore errors (will fail later anyway)
|
||||
os.Remove(setting.listen)
|
||||
l, err = net.Listen("unix", setting.listen)
|
||||
} else {
|
||||
listenAddr := setting.listen
|
||||
if !strings.Contains(listenAddr, ":") {
|
||||
listenAddr = ":" + listenAddr
|
||||
}
|
||||
l, err = net.Listen("tcp", listenAddr)
|
||||
for _, listenAddr := range setting.listen {
|
||||
go func(addr string) {
|
||||
fmt.Printf("Listening on %s...\n", addr)
|
||||
|
||||
var l net.Listener
|
||||
var err error
|
||||
|
||||
if strings.HasPrefix(addr, "/") {
|
||||
// Delete existing socket file, ignore errors (will fail later anyway)
|
||||
os.Remove(addr)
|
||||
l, err = net.Listen("unix", addr)
|
||||
} else {
|
||||
if !strings.Contains(addr, ":") {
|
||||
addr = ":" + addr
|
||||
}
|
||||
l, err = net.Listen("tcp", addr)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
http.Serve(l, handlers.LoggingHandler(os.Stdout, accessHandler(mux)))
|
||||
}(listenAddr)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Start HTTP server
|
||||
http.HandleFunc("/", invalidHandler)
|
||||
http.HandleFunc("/bird", birdHandler)
|
||||
http.HandleFunc("/bird6", birdHandler)
|
||||
http.HandleFunc("/traceroute", tracerouteHandler)
|
||||
http.HandleFunc("/traceroute6", tracerouteHandler)
|
||||
http.Serve(l, handlers.LoggingHandler(os.Stdout, accessHandler(http.DefaultServeMux)))
|
||||
select {}
|
||||
}
|
||||
|
@@ -11,12 +11,12 @@ import (
|
||||
)
|
||||
|
||||
type viperSettingType struct {
|
||||
BirdSocket string `mapstructure:"bird_socket"`
|
||||
Listen string `mapstructure:"listen"`
|
||||
AllowedNets string `mapstructure:"allowed_ips"`
|
||||
TracerouteBin string `mapstructure:"traceroute_bin"`
|
||||
TracerouteFlags string `mapstructure:"traceroute_flags"`
|
||||
TracerouteRaw bool `mapstructure:"traceroute_raw"`
|
||||
BirdSocket string `mapstructure:"bird_socket"`
|
||||
Listen []string `mapstructure:"listen"`
|
||||
AllowedNets string `mapstructure:"allowed_ips"`
|
||||
TracerouteBin string `mapstructure:"traceroute_bin"`
|
||||
TracerouteFlags string `mapstructure:"traceroute_flags"`
|
||||
TracerouteRaw bool `mapstructure:"traceroute_raw"`
|
||||
}
|
||||
|
||||
// Parse settings with viper, and convert to legacy setting format
|
||||
@@ -37,7 +37,7 @@ func parseSettings() {
|
||||
pflag.String("bird", "/var/run/bird/bird.ctl", "socket file for bird, set either in parameter or environment variable BIRD_SOCKET")
|
||||
viper.BindPFlag("bird_socket", pflag.Lookup("bird"))
|
||||
|
||||
pflag.String("listen", "8000", "listen address, set either in parameter or environment variable BIRDLG_PROXY_PORT")
|
||||
pflag.StringSlice("listen", []string{"8000"}, "listen address, set either in parameter or environment variable BIRDLG_PROXY_PORT")
|
||||
viper.BindPFlag("listen", pflag.Lookup("listen"))
|
||||
|
||||
pflag.String("allowed", "", "IPs or networks allowed to access this proxy, separated by commas. Don't set to allow all IPs.")
|
||||
|
Reference in New Issue
Block a user