commit 4a82c7db0e62f44206b9e0d496a9de6cc54667fc Author: Markus Pesch Date: Mon Jun 14 09:53:26 2021 +0200 Initial Commit 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()) +}