From 4a82c7db0e62f44206b9e0d496a9de6cc54667fc Mon Sep 17 00:00:00 2001 From: Markus Pesch Date: Mon, 14 Jun 2021 09:53:26 +0200 Subject: [PATCH] Initial Commit --- .editorconfig | 15 ++++++ .gitignore | 1 + .golangci.yml | 28 +++++++++++ Dockerfile | 32 +++++++++++++ LICENSE | 13 ++++++ Makefile | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 7 +++ go.mod | 5 ++ go.sum | 21 +++++++++ main.go | 40 ++++++++++++++++ 10 files changed, 288 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .golangci.yml create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..dd69de0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = false + +[Makefile] +indent_style = tab \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7c63416 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +getpsrc \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..f7e2c3b --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,28 @@ +run: + skip-dirs: + - it + timeout: 10m + tests: true + +linters: + disable-all: true + enable: + # Default + - deadcode + - errcheck + - gosimple + - govet + - ineffassign + - staticcheck + - structcheck + - typecheck + - unused + - varcheck + + # Additionally linters + - bodyclose + - misspell + - nilerr + - rowserrcheck + - sqlclosecheck + - unparam \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9555c3e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +ARG BASE_IMAGE +ARG BUILD_IMAGE + +# BUILD +# ===================================================================== +FROM ${BUILD_IMAGE} AS build + +ARG GONOPROXY +ARG GONOSUMDB +ARG GOPRIVATE +ARG GOPROXY +ARG GOSUMDB +ARG VERSION + +COPY ./ /workspace + +RUN cd /workspace && \ + GONOPROXY=${GONOPROXY} \ + GONOSUMDB=${GONOSUMDB} \ + GOPRIVATE=${GOPRIVATE} \ + GOPROXY=${GOPROXY} \ + GOSUMDB=${GOSUMDB} \ + VERSION=${VERSION} \ + make all + +# TARGET +# ===================================================================== +FROM ${BASE_IMAGE} + +COPY --from=build /workspace/getpsrc /usr/bin/getpsrc + +ENTRYPOINT [ "/usr/bin/getpsrc" ] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5a82408 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2019 Markus Pesch + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..740cf96 --- /dev/null +++ b/Makefile @@ -0,0 +1,126 @@ +# VERSION +VERSION?=$(shell git describe --abbrev=0)+hash.$(shell git rev-parse --short HEAD) + +# CONTAINER_RUNTIME +CONTAINER_RUNTIME?=$(shell which docker) + +# BUILD_IMAGE +BUILD_IMAGE_REGISTRY_HOST?=docker.io +BUILD_IMAGE_NAMESPACE=library +BUILD_IMAGE_REPOSITORY=golang +BUILD_IMAGE_VERSION?=1.16 +BUILD_IMAGE_FULLY_QUALIFIED:=${BUILD_IMAGE_REGISTRY_HOST}/${BUILD_IMAGE_NAMESPACE}/${BUILD_IMAGE_REPOSITORY}:${BUILD_IMAGE_VERSION} + +# BASE_IMAGE +BASE_IMAGE_REGISTRY_HOST?=docker.io +BASE_IMAGE_NAMESPACE=library +BASE_IMAGE_REPOSITORY=busybox +BASE_IMAGE_VERSION?=latest +BASE_IMAGE_FULLY_QUALIFIED=${BASE_IMAGE_REGISTRY_HOST}/${BASE_IMAGE_NAMESPACE}/${BASE_IMAGE_REPOSITORY}:${BASE_IMAGE_VERSION} + +# CONTAINER_IMAGE +CONTAINER_IMAGE_REGISTRY_HOST?=docker.io +CONTAINER_IMAGE_NAMESPACE=volkerraschek +CONTAINER_IMAGE_REPOSITORY=getpsrc +CONTAINER_IMAGE_VERSION?=latest +CONTAINER_IMAGE_FULLY_QUALIFIED=${CONTAINER_IMAGE_REGISTRY_HOST}/${CONTAINER_IMAGE_NAMESPACE}/${CONTAINER_IMAGE_REPOSITORY}:${CONTAINER_IMAGE_VERSION} +CONTAINER_IMAGE_UNQUALIFIED=${CONTAINER_IMAGE_NAMESPACE}/${CONTAINER_IMAGE_REPOSITORY}:${CONTAINER_IMAGE_VERSION} + +# EXECUTABLES +# ============================================================================== +EXECUTABLE_TARGETS=getpsrc + +PHONY=all +all: clean ${EXECUTABLE_TARGETS} + +getpsrc: + GOPRIVATE=$(shell go env GOPRIVATE) \ + GOPROXY=$(shell go env GOPROXY) \ + GONOPROXY=$(shell go env GONOPROXY) \ + GONOSUMDB=$(shell go env GONOSUMDB) \ + GOSUMDB=$(shell go env GOSUMDB) \ + go build -tags netgo -ldflags "-X main.version=${VERSION}" -o ${@} main.go + +# CLEAN +# ============================================================================== +PHONY+=clean +clean: + rm --force --recursive $(shell pwd)/getpsrc* + +# GOLANGCI-LINT +# ============================================================================== +PHONY+=golangci-lint +golangci-lint: + golangci-lint run --concurrency=$(shell nproc) + +# GOSEC +# ============================================================================== +PHONY+=gosec +gosec: + gosec $(shell pwd)/... + +# CONTAINER-IMAGE +# ============================================================================== +PHONY+=container-image/build +container-image/build: + ${CONTAINER_RUNTIME} build \ + --build-arg BASE_IMAGE=${BASE_IMAGE_FULLY_QUALIFIED} \ + --build-arg BUILD_IMAGE=${BUILD_IMAGE_FULLY_QUALIFIED} \ + --build-arg GOPRIVATE=$(shell go env GOPRIVATE) \ + --build-arg GOPROXY=$(shell go env GOPROXY) \ + --build-arg GONOPROXY=$(shell go env GONOPROXY) \ + --build-arg GONOSUMDB=$(shell go env GONOSUMDB) \ + --build-arg GOSUMDB=$(shell go env GOSUMDB) \ + --build-arg VERSION=${VERSION} \ + --file ./Dockerfile \ + --no-cache \ + --tag ${CONTAINER_IMAGE_UNQUALIFIED} \ + --tag ${CONTAINER_IMAGE_FULLY_QUALIFIED} \ + . + +PHONY+=container-image/push +container-image/push: container-image/build + ${CONTAINER_RUNTIME} push ${CONTAINER_IMAGE_FULLY_QUALIFIED} + +# CONTAINER STEPS - EXECUTABLE +# ============================================================================== +PHONY+=container-run/all +container-run/all: + $(MAKE) container-run COMMAND=${@:container-run/%=%} + +PHONY+=${EXECUTABLE_TARGETS:%=container-run/%} +${EXECUTABLE_TARGETS:%=container-run/%}: + $(MAKE) container-run COMMAND=${@:container-run/%=%} + +# CONTAINER STEPS - CLEAN +# ============================================================================== +PHONY+=container-run/clean +container-run/clean: + $(MAKE) container-run COMMAND=${@:container-run/%=%} + +# GENERAL CONTAINER COMMAND +# ============================================================================== +PHONY+=container-run +container-run: + ${CONTAINER_RUNTIME} run \ + --env CONTAINER_IMAGE_VERSION=${CONTAINER_IMAGE_VERSION} \ + --env GONOPROXY=$(shell go env GONOPROXY) \ + --env GONOSUMDB=$(shell go env GONOSUMDB) \ + --env GOPRIVATE=$(shell go env GOPRIVATE) \ + --env GOPROXY=$(shell go env GOPROXY) \ + --env GOSUMDB=$(shell go env GOSUMDB) \ + --env VERSION=${VERSION} \ + --net=host \ + --rm \ + --volume /tmp:/tmp \ + --volume ${HOME}/go:/root/go \ + --volume $(shell pwd):/workspace \ + --workdir /workspace \ + ${BUILD_IMAGE_FULLY_QUALIFIED} \ + make ${COMMAND} + +# PHONY +# ============================================================================== +# Declare the contents of the PHONY variable as phony. We keep that information +# in a variable so we can use it in if_changed. +.PHONY: ${PHONY} diff --git a/README.md b/README.md new file mode 100644 index 0000000..0ec1a27 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# getpsrc + +`getpsrc` is a small programme to determine the src routing ip for an external ip. + +`getpsrc` serves as an alternative to `ip route get | awk ... ` because `ip +route get` can return different output depending on the environment and +therefore the construct is unsafe. diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1da1ca2 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/volker-raschek/getpsrc + +go 1.16 + +require github.com/google/gopacket v1.1.20-0.20210429153827-3eaba0894325 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..4d46497 --- /dev/null +++ b/go.sum @@ -0,0 +1,21 @@ +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= +github.com/google/gopacket v1.1.20-0.20210429153827-3eaba0894325 h1:YmIcZ5Var3BAQ64AW98Iiys5Ih4fiU0xK41+8isC5Ec= +github.com/google/gopacket v1.1.20-0.20210429153827-3eaba0894325/go.mod h1:riddUzxTSBpJXk3qBHtYr4qOhFhT6k/1c0E3qkQjQpA= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/main.go b/main.go new file mode 100644 index 0000000..ba6155e --- /dev/null +++ b/main.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" + "log" + "net" + "os" + "strings" + + "github.com/google/gopacket/routing" +) + +func main() { + ips := os.Args[1:] + switch { + case len(ips) == 0: + log.Fatal("Expect exactly one argument") + case len(ips) >= 2: + log.Fatal("Expect only one argument") + } + + rawIP := strings.Split(ips[0], "/")[0] + + ip := net.ParseIP(rawIP) + if ip == nil { + log.Fatal("failed to parse raw ip") + } + + router, err := routing.New() + if err != nil { + log.Fatalf("failed to get new routing instance: %v", err.Error()) + } + + _, _, prefferedSrc, err := router.Route(ip) + if err != nil { + log.Fatalf("failed to find gateway for ip: %v", err.Error()) + } + + fmt.Fprintln(os.Stdout, prefferedSrc.String()) +}