From ac62eab8597bfe72bd7b55860ad9047b931d68ef Mon Sep 17 00:00:00 2001 From: Peter Kurfer Date: Thu, 9 Apr 2020 00:59:22 +0200 Subject: [PATCH 1/9] Initial commit http_proxy --- pkg/plugins/http_proxy/Makefile | 44 +++++++++++++++++++++++++++++++++ pkg/plugins/http_proxy/init.go | 13 ++++++++++ pkg/plugins/http_proxy/main.go | 23 +++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 pkg/plugins/http_proxy/Makefile create mode 100644 pkg/plugins/http_proxy/init.go create mode 100644 pkg/plugins/http_proxy/main.go diff --git a/pkg/plugins/http_proxy/Makefile b/pkg/plugins/http_proxy/Makefile new file mode 100644 index 0000000..db2df0a --- /dev/null +++ b/pkg/plugins/http_proxy/Makefile @@ -0,0 +1,44 @@ +VERSION = $(shell git describe --dirty --tags --always) +DIR = $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) +PKGS = $(shell go list ./...) +TEST_PKGS = $(shell find . -type f -name "*_test.go" -printf '%h\n' | sort -u) +GOARGS = GOOS=linux GOARCH=amd64 +GO_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" +GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo +GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l" +PLUGIN_NAME = $(shell basename $(DIR)).so +OUT_DIR = $(DIR)../../../plugins +DEBUG_PORT = 2345 + +.PHONY: deps format compile test cli-cover-report html-cover-report + +all: format compile test + +deps: + @go mod tidy + @go build -buildmode=plugin -v $(DIR)... + +format: + @go fmt $(PKGS) + +compile: deps + @mkdir -p $(OUT_DIR) +ifdef DEBUG + @echo 'Compiling for debugging...' + @$(GOARGS) go build $(GO_DEBUG_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR) +else ifdef CONTAINER + @$(GOARGS) go build $(GO_CONTAINER_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR) +else + @$(GOARGS) go build $(GO_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR) +endif + +test: + @go test -coverprofile=./cov-raw.out -v $(TEST_PKGS) + @cat ./cov-raw.out | grep -v "generated" > ./cov.out + @rm -f $(DIR)$(PLUGIN_NAME) + +cli-cover-report: + @go tool cover -func=cov.out + +html-cover-report: + @go tool cover -html=cov.out -o .coverage.html \ No newline at end of file diff --git a/pkg/plugins/http_proxy/init.go b/pkg/plugins/http_proxy/init.go new file mode 100644 index 0000000..22ef15e --- /dev/null +++ b/pkg/plugins/http_proxy/init.go @@ -0,0 +1,13 @@ +package main + +import ( + "github.com/baez90/inetmock/pkg/logging" + "go.uber.org/zap" +) + +func init() { + logger, _ := logging.CreateLogger() + logger = logger.With( + zap.String("ProtocolHandler", name), + ) +} diff --git a/pkg/plugins/http_proxy/main.go b/pkg/plugins/http_proxy/main.go new file mode 100644 index 0000000..9b644a0 --- /dev/null +++ b/pkg/plugins/http_proxy/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "github.com/baez90/inetmock/internal/config" + "go.uber.org/zap" + "sync" +) + +const ( + name = "http_proxy" +) + +type httpProxy struct { + logger *zap.Logger +} + +func (h httpProxy) Run(config config.HandlerConfig) { + panic("implement me") +} + +func (h httpProxy) Shutdown(wg *sync.WaitGroup) { + panic("implement me") +} From ca1ac7d89a2d5aa9876fcad8212a4d465f97beaa Mon Sep 17 00:00:00 2001 From: Peter Kurfer Date: Sat, 11 Apr 2020 15:31:08 +0200 Subject: [PATCH 2/9] Move plugins to top level directory in repository - update Makefiles and GoReleaser config - update dependencies --- .gitignore | 3 +- .goreleaser.yml | 2 +- Makefile | 9 +- go.mod | 15 +- go.sum | 67 ++++-- pkg/plugins/dns_mock/go.mod | 22 -- pkg/plugins/go.mod | 3 - pkg/plugins/http_mock/go.mod | 21 -- pkg/plugins/tls_interceptor/go.mod | 21 -- .../http_proxy => plugins/dns_mock}/Makefile | 3 +- plugins/dns_mock/fake_main.go | 5 + {pkg/plugins => plugins}/dns_mock/fallback.go | 0 .../dns_mock/fallback_test.go | 0 plugins/dns_mock/go.mod | 14 ++ .../dns_mock}/go.sum | 22 +- {pkg/plugins => plugins}/dns_mock/init.go | 0 {pkg/plugins => plugins}/dns_mock/main.go | 0 .../dns_mock/protocol_options.go | 0 .../dns_mock/regex_handler.go | 0 plugins/go.mod | 3 + .../dns_mock => plugins/http_mock}/Makefile | 3 +- plugins/http_mock/fake_main.go | 5 + plugins/http_mock/go.mod | 11 + {pkg/plugins => plugins}/http_mock/go.sum | 15 -- {pkg/plugins => plugins}/http_mock/init.go | 0 {pkg/plugins => plugins}/http_mock/main.go | 0 .../http_mock/protocol_options.go | 0 .../http_mock/regex_router.go | 0 .../http_proxy}/Makefile | 3 +- plugins/http_proxy/fake_main.go | 5 + plugins/http_proxy/go.mod | 10 + plugins/http_proxy/go.sum | 215 ++++++++++++++++++ {pkg/plugins => plugins}/http_proxy/init.go | 0 {pkg/plugins => plugins}/http_proxy/main.go | 0 .../tls_interceptor}/Makefile | 5 +- .../tls_interceptor/addr_utils.go | 0 .../tls_interceptor/addr_utils_test.go | 0 .../tls_interceptor/cert_store.go | 0 .../tls_interceptor/cert_store_test.go | 0 .../tls_interceptor/certs.go | 0 .../tls_interceptor/certs_test.go | 0 plugins/tls_interceptor/fake_main.go | 5 + .../tls_interceptor/generate_ca_cmd.go | 0 plugins/tls_interceptor/go.mod | 12 + .../tls_interceptor}/go.sum | 20 -- .../tls_interceptor/init.go | 0 .../tls_interceptor/main.go | 0 .../tls_interceptor/protocol_options.go | 0 .../tls_interceptor/proxy.go | 0 .../tls_interceptor/proxy_conn.go | 0 .../tls_interceptor/test_setup.go | 0 .../tls_interceptor/time_source.go | 0 52 files changed, 367 insertions(+), 152 deletions(-) delete mode 100644 pkg/plugins/dns_mock/go.mod delete mode 100644 pkg/plugins/go.mod delete mode 100644 pkg/plugins/http_mock/go.mod delete mode 100644 pkg/plugins/tls_interceptor/go.mod rename {pkg/plugins/http_proxy => plugins/dns_mock}/Makefile (97%) create mode 100644 plugins/dns_mock/fake_main.go rename {pkg/plugins => plugins}/dns_mock/fallback.go (100%) rename {pkg/plugins => plugins}/dns_mock/fallback_test.go (100%) create mode 100644 plugins/dns_mock/go.mod rename {pkg/plugins/tls_interceptor => plugins/dns_mock}/go.sum (95%) rename {pkg/plugins => plugins}/dns_mock/init.go (100%) rename {pkg/plugins => plugins}/dns_mock/main.go (100%) rename {pkg/plugins => plugins}/dns_mock/protocol_options.go (100%) rename {pkg/plugins => plugins}/dns_mock/regex_handler.go (100%) create mode 100644 plugins/go.mod rename {pkg/plugins/dns_mock => plugins/http_mock}/Makefile (97%) create mode 100644 plugins/http_mock/fake_main.go create mode 100644 plugins/http_mock/go.mod rename {pkg/plugins => plugins}/http_mock/go.sum (94%) rename {pkg/plugins => plugins}/http_mock/init.go (100%) rename {pkg/plugins => plugins}/http_mock/main.go (100%) rename {pkg/plugins => plugins}/http_mock/protocol_options.go (100%) rename {pkg/plugins => plugins}/http_mock/regex_router.go (100%) rename {pkg/plugins/tls_interceptor => plugins/http_proxy}/Makefile (97%) create mode 100644 plugins/http_proxy/fake_main.go create mode 100644 plugins/http_proxy/go.mod create mode 100644 plugins/http_proxy/go.sum rename {pkg/plugins => plugins}/http_proxy/init.go (100%) rename {pkg/plugins => plugins}/http_proxy/main.go (100%) rename {pkg/plugins/http_mock => plugins/tls_interceptor}/Makefile (96%) rename {pkg/plugins => plugins}/tls_interceptor/addr_utils.go (100%) rename {pkg/plugins => plugins}/tls_interceptor/addr_utils_test.go (100%) rename {pkg/plugins => plugins}/tls_interceptor/cert_store.go (100%) rename {pkg/plugins => plugins}/tls_interceptor/cert_store_test.go (100%) rename {pkg/plugins => plugins}/tls_interceptor/certs.go (100%) rename {pkg/plugins => plugins}/tls_interceptor/certs_test.go (100%) create mode 100644 plugins/tls_interceptor/fake_main.go rename {pkg/plugins => plugins}/tls_interceptor/generate_ca_cmd.go (100%) create mode 100644 plugins/tls_interceptor/go.mod rename {pkg/plugins/dns_mock => plugins/tls_interceptor}/go.sum (92%) rename {pkg/plugins => plugins}/tls_interceptor/init.go (100%) rename {pkg/plugins => plugins}/tls_interceptor/main.go (100%) rename {pkg/plugins => plugins}/tls_interceptor/protocol_options.go (100%) rename {pkg/plugins => plugins}/tls_interceptor/proxy.go (100%) rename {pkg/plugins => plugins}/tls_interceptor/proxy_conn.go (100%) rename {pkg/plugins => plugins}/tls_interceptor/test_setup.go (100%) rename {pkg/plugins => plugins}/tls_interceptor/time_source.go (100%) diff --git a/.gitignore b/.gitignore index da63680..84ce54b 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ main ############### .idea/ -dist/ \ No newline at end of file +dist/ +out/ \ No newline at end of file diff --git a/.goreleaser.yml b/.goreleaser.yml index a40c8df..dad29e5 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -22,7 +22,7 @@ archives: wrap_in_directory: true files: - config.yaml - - plugins/*.so + - "*.so" checksum: name_template: 'checksums.txt' snapshot: diff --git a/Makefile b/Makefile index 91cab21..b8ec306 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,14 @@ -VERSION = $(shell git describe --dirty --tags --always) +VERSst/pluginsION = $(shell git describe --dirty --tags --always) DIR = $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) BUILD_PATH = $(DIR)/main.go PKGS = $(shell go list ./...) -TEST_PKGS = $(shell find . -type f -name "*_test.go" -not -path "./pkg/plugins/*" -printf '%h\n' | sort -u) +TEST_PKGS = $(shell find . -type f -name "*_test.go" -not -path "./plugins/*" -printf '%h\n' | sort -u) GOARGS = GOOS=linux GOARCH=amd64 GO_BUILD_ARGS = -ldflags="-w -s" GO_CONTAINER_BUILD_ARGS = -ldflags="-w -s" -a -installsuffix cgo GO_DEBUG_BUILD_ARGS = -gcflags "all=-N -l" BINARY_NAME = inetmock -PLUGINS = $(wildcard $(DIR)pkg/plugins/*/.) +PLUGINS = $(wildcard $(DIR)plugins/*/.) DEBUG_PORT = 2345 DEBUG_ARGS?= --development-logs=true INETMOCK_PLUGINS_DIRECTORY = $(DIR) @@ -19,7 +19,7 @@ all: clean format compile test plugins clean: @find $(DIR) -type f \( -name "*.out" -or -name "*.so" \) -exec rm -f {} \; - @rm -rf $(DIR)plugins + @rm -rf $(DIR)*.so @rm -f $(DIR)$(BINARY_NAME) $(DIR)main format: @@ -27,6 +27,7 @@ format: deps: @go mod tidy + @go get -u @go build -v $(BUILD_PATH) compile: deps diff --git a/go.mod b/go.mod index 079bcaa..1cd0e7c 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,18 @@ module github.com/baez90/inetmock go 1.13 require ( - github.com/spf13/cobra v0.0.6 + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/mitchellh/mapstructure v1.2.2 // indirect + github.com/pelletier/go-toml v1.7.0 // indirect + github.com/spf13/afero v1.2.2 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/cobra v1.0.0 + github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.4.0 + github.com/spf13/viper v1.6.3 go.uber.org/zap v1.14.1 - golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe // indirect + golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa // indirect + golang.org/x/text v0.3.2 // indirect golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 // indirect - gopkg.in/yaml.v2 v2.2.8 // indirect + gopkg.in/ini.v1 v1.55.0 // indirect ) diff --git a/go.sum b/go.sum index 6eedcc3..34c4685 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,7 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= @@ -20,8 +21,9 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -36,7 +38,10 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -46,10 +51,12 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -57,16 +64,22 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= +github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -85,30 +98,38 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= -github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs= +github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -127,9 +148,7 @@ go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -148,27 +167,27 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= +golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -183,10 +202,14 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ= +gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/plugins/dns_mock/go.mod b/pkg/plugins/dns_mock/go.mod deleted file mode 100644 index aa9d153..0000000 --- a/pkg/plugins/dns_mock/go.mod +++ /dev/null @@ -1,22 +0,0 @@ -module github.com/baez90/inetmock/pkg/plugins/dns_mock - -go 1.14 - -require ( - github.com/baez90/inetmock v0.0.1 - github.com/fsnotify/fsnotify v1.4.9 // indirect - github.com/miekg/dns v1.1.29 - github.com/mitchellh/mapstructure v1.2.2 // indirect - github.com/pelletier/go-toml v1.7.0 // indirect - github.com/spf13/afero v1.2.2 // indirect - github.com/spf13/cast v1.3.1 // indirect - github.com/spf13/cobra v1.0.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/viper v1.6.3 - go.uber.org/zap v1.14.1 - golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa // indirect - golang.org/x/text v0.3.2 // indirect - gopkg.in/ini.v1 v1.55.0 // indirect -) - -replace github.com/baez90/inetmock v0.0.1 => ../../../ diff --git a/pkg/plugins/go.mod b/pkg/plugins/go.mod deleted file mode 100644 index 6ec155b..0000000 --- a/pkg/plugins/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/baez90/inetmock/pkg/plugins - -go 1.14 diff --git a/pkg/plugins/http_mock/go.mod b/pkg/plugins/http_mock/go.mod deleted file mode 100644 index 410511e..0000000 --- a/pkg/plugins/http_mock/go.mod +++ /dev/null @@ -1,21 +0,0 @@ -module github.com/baez90/inetmock/pkg/plugins/http_mock - -go 1.14 - -require ( - github.com/baez90/inetmock v0.0.1 - github.com/fsnotify/fsnotify v1.4.9 // indirect - github.com/mitchellh/mapstructure v1.2.2 // indirect - github.com/pelletier/go-toml v1.7.0 // indirect - github.com/spf13/afero v1.2.2 // indirect - github.com/spf13/cast v1.3.1 // indirect - github.com/spf13/cobra v1.0.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/viper v1.6.3 - go.uber.org/zap v1.14.1 - golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa // indirect - golang.org/x/text v0.3.2 // indirect - gopkg.in/ini.v1 v1.55.0 // indirect -) - -replace github.com/baez90/inetmock v0.0.1 => ../../../ diff --git a/pkg/plugins/tls_interceptor/go.mod b/pkg/plugins/tls_interceptor/go.mod deleted file mode 100644 index a8123ce..0000000 --- a/pkg/plugins/tls_interceptor/go.mod +++ /dev/null @@ -1,21 +0,0 @@ -module github.com/baez90/inetmock/pkg/plugins/tls_interceptor - -go 1.14 - -require ( - github.com/baez90/inetmock v0.0.1 - github.com/fsnotify/fsnotify v1.4.9 // indirect - github.com/mitchellh/mapstructure v1.2.2 // indirect - github.com/pelletier/go-toml v1.7.0 // indirect - github.com/spf13/afero v1.2.2 // indirect - github.com/spf13/cast v1.3.1 // indirect - github.com/spf13/cobra v1.0.0 - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/viper v1.6.3 - go.uber.org/zap v1.14.1 - golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa // indirect - golang.org/x/text v0.3.2 // indirect - gopkg.in/ini.v1 v1.55.0 // indirect -) - -replace github.com/baez90/inetmock v0.0.1 => ../../../ diff --git a/pkg/plugins/http_proxy/Makefile b/plugins/dns_mock/Makefile similarity index 97% rename from pkg/plugins/http_proxy/Makefile rename to plugins/dns_mock/Makefile index db2df0a..0086189 100644 --- a/pkg/plugins/http_proxy/Makefile +++ b/plugins/dns_mock/Makefile @@ -7,7 +7,7 @@ GO_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l" PLUGIN_NAME = $(shell basename $(DIR)).so -OUT_DIR = $(DIR)../../../plugins +OUT_DIR = $(DIR)../../ DEBUG_PORT = 2345 .PHONY: deps format compile test cli-cover-report html-cover-report @@ -16,6 +16,7 @@ all: format compile test deps: @go mod tidy + @go get -u @go build -buildmode=plugin -v $(DIR)... format: diff --git a/plugins/dns_mock/fake_main.go b/plugins/dns_mock/fake_main.go new file mode 100644 index 0000000..fa0b8bf --- /dev/null +++ b/plugins/dns_mock/fake_main.go @@ -0,0 +1,5 @@ +package main + +func main() { + panic("should not every be called") +} diff --git a/pkg/plugins/dns_mock/fallback.go b/plugins/dns_mock/fallback.go similarity index 100% rename from pkg/plugins/dns_mock/fallback.go rename to plugins/dns_mock/fallback.go diff --git a/pkg/plugins/dns_mock/fallback_test.go b/plugins/dns_mock/fallback_test.go similarity index 100% rename from pkg/plugins/dns_mock/fallback_test.go rename to plugins/dns_mock/fallback_test.go diff --git a/plugins/dns_mock/go.mod b/plugins/dns_mock/go.mod new file mode 100644 index 0000000..f02f77c --- /dev/null +++ b/plugins/dns_mock/go.mod @@ -0,0 +1,14 @@ +module github.com/baez90/inetmock/plugins/dns_mock + +go 1.14 + +require ( + github.com/baez90/inetmock v0.0.1 + github.com/miekg/dns v1.1.29 + github.com/spf13/viper v1.6.3 + go.uber.org/zap v1.14.1 + golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 // indirect + golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect +) + +replace github.com/baez90/inetmock v0.0.1 => ../../ diff --git a/pkg/plugins/tls_interceptor/go.sum b/plugins/dns_mock/go.sum similarity index 95% rename from pkg/plugins/tls_interceptor/go.sum rename to plugins/dns_mock/go.sum index 4163d9e..3a5b570 100644 --- a/pkg/plugins/tls_interceptor/go.sum +++ b/plugins/dns_mock/go.sum @@ -21,7 +21,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -69,8 +68,9 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg= +github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -79,7 +79,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= @@ -108,22 +107,17 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -158,6 +152,8 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 h1:DOmugCavvUtnUD114C1Wh+UgTgQZ4pMLzXxi1pSt+/Y= +golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= @@ -171,24 +167,26 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -214,7 +212,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ= gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -222,7 +219,6 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/plugins/dns_mock/init.go b/plugins/dns_mock/init.go similarity index 100% rename from pkg/plugins/dns_mock/init.go rename to plugins/dns_mock/init.go diff --git a/pkg/plugins/dns_mock/main.go b/plugins/dns_mock/main.go similarity index 100% rename from pkg/plugins/dns_mock/main.go rename to plugins/dns_mock/main.go diff --git a/pkg/plugins/dns_mock/protocol_options.go b/plugins/dns_mock/protocol_options.go similarity index 100% rename from pkg/plugins/dns_mock/protocol_options.go rename to plugins/dns_mock/protocol_options.go diff --git a/pkg/plugins/dns_mock/regex_handler.go b/plugins/dns_mock/regex_handler.go similarity index 100% rename from pkg/plugins/dns_mock/regex_handler.go rename to plugins/dns_mock/regex_handler.go diff --git a/plugins/go.mod b/plugins/go.mod new file mode 100644 index 0000000..abefadf --- /dev/null +++ b/plugins/go.mod @@ -0,0 +1,3 @@ +module github.com/baez90/inetmock/plugins + +go 1.14 diff --git a/pkg/plugins/dns_mock/Makefile b/plugins/http_mock/Makefile similarity index 97% rename from pkg/plugins/dns_mock/Makefile rename to plugins/http_mock/Makefile index e1074cd..ea47347 100644 --- a/pkg/plugins/dns_mock/Makefile +++ b/plugins/http_mock/Makefile @@ -7,7 +7,7 @@ GO_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l" PLUGIN_NAME = $(shell basename $(DIR)).so -OUT_DIR = $(DIR)../../../plugins +OUT_DIR = $(DIR)../../ DEBUG_PORT = 2345 .PHONY: deps format compile test cli-cover-report html-cover-report @@ -16,6 +16,7 @@ all: format compile test deps: @go mod tidy + @go get -u @go build -buildmode=plugin -v $(DIR)... format: diff --git a/plugins/http_mock/fake_main.go b/plugins/http_mock/fake_main.go new file mode 100644 index 0000000..fa0b8bf --- /dev/null +++ b/plugins/http_mock/fake_main.go @@ -0,0 +1,5 @@ +package main + +func main() { + panic("should not every be called") +} diff --git a/plugins/http_mock/go.mod b/plugins/http_mock/go.mod new file mode 100644 index 0000000..a734142 --- /dev/null +++ b/plugins/http_mock/go.mod @@ -0,0 +1,11 @@ +module github.com/baez90/inetmock/plugins/http_mock + +go 1.14 + +require ( + github.com/baez90/inetmock v0.0.1 + github.com/spf13/viper v1.6.3 + go.uber.org/zap v1.14.1 +) + +replace github.com/baez90/inetmock v0.0.1 => ../../ diff --git a/pkg/plugins/http_mock/go.sum b/plugins/http_mock/go.sum similarity index 94% rename from pkg/plugins/http_mock/go.sum rename to plugins/http_mock/go.sum index eb1435f..34c4685 100644 --- a/pkg/plugins/http_mock/go.sum +++ b/plugins/http_mock/go.sum @@ -21,7 +21,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -70,7 +69,6 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -79,7 +77,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= @@ -108,23 +105,17 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= -github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -182,14 +173,10 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -215,7 +202,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ= gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -223,7 +209,6 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/plugins/http_mock/init.go b/plugins/http_mock/init.go similarity index 100% rename from pkg/plugins/http_mock/init.go rename to plugins/http_mock/init.go diff --git a/pkg/plugins/http_mock/main.go b/plugins/http_mock/main.go similarity index 100% rename from pkg/plugins/http_mock/main.go rename to plugins/http_mock/main.go diff --git a/pkg/plugins/http_mock/protocol_options.go b/plugins/http_mock/protocol_options.go similarity index 100% rename from pkg/plugins/http_mock/protocol_options.go rename to plugins/http_mock/protocol_options.go diff --git a/pkg/plugins/http_mock/regex_router.go b/plugins/http_mock/regex_router.go similarity index 100% rename from pkg/plugins/http_mock/regex_router.go rename to plugins/http_mock/regex_router.go diff --git a/pkg/plugins/tls_interceptor/Makefile b/plugins/http_proxy/Makefile similarity index 97% rename from pkg/plugins/tls_interceptor/Makefile rename to plugins/http_proxy/Makefile index db2df0a..0086189 100644 --- a/pkg/plugins/tls_interceptor/Makefile +++ b/plugins/http_proxy/Makefile @@ -7,7 +7,7 @@ GO_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l" PLUGIN_NAME = $(shell basename $(DIR)).so -OUT_DIR = $(DIR)../../../plugins +OUT_DIR = $(DIR)../../ DEBUG_PORT = 2345 .PHONY: deps format compile test cli-cover-report html-cover-report @@ -16,6 +16,7 @@ all: format compile test deps: @go mod tidy + @go get -u @go build -buildmode=plugin -v $(DIR)... format: diff --git a/plugins/http_proxy/fake_main.go b/plugins/http_proxy/fake_main.go new file mode 100644 index 0000000..fa0b8bf --- /dev/null +++ b/plugins/http_proxy/fake_main.go @@ -0,0 +1,5 @@ +package main + +func main() { + panic("should not every be called") +} diff --git a/plugins/http_proxy/go.mod b/plugins/http_proxy/go.mod new file mode 100644 index 0000000..dc5e230 --- /dev/null +++ b/plugins/http_proxy/go.mod @@ -0,0 +1,10 @@ +module github.com/baez90/inetmock/plugins/http_proxy + +go 1.14 + +require ( + github.com/baez90/inetmock v0.0.1 + go.uber.org/zap v1.14.1 +) + +replace github.com/baez90/inetmock v0.0.1 => ../../ diff --git a/plugins/http_proxy/go.sum b/plugins/http_proxy/go.sum new file mode 100644 index 0000000..5b68430 --- /dev/null +++ b/plugins/http_proxy/go.sum @@ -0,0 +1,215 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= +github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= +github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs= +github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= +go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= +golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ= +gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/pkg/plugins/http_proxy/init.go b/plugins/http_proxy/init.go similarity index 100% rename from pkg/plugins/http_proxy/init.go rename to plugins/http_proxy/init.go diff --git a/pkg/plugins/http_proxy/main.go b/plugins/http_proxy/main.go similarity index 100% rename from pkg/plugins/http_proxy/main.go rename to plugins/http_proxy/main.go diff --git a/pkg/plugins/http_mock/Makefile b/plugins/tls_interceptor/Makefile similarity index 96% rename from pkg/plugins/http_mock/Makefile rename to plugins/tls_interceptor/Makefile index e1074cd..0086189 100644 --- a/pkg/plugins/http_mock/Makefile +++ b/plugins/tls_interceptor/Makefile @@ -7,7 +7,7 @@ GO_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l" PLUGIN_NAME = $(shell basename $(DIR)).so -OUT_DIR = $(DIR)../../../plugins +OUT_DIR = $(DIR)../../ DEBUG_PORT = 2345 .PHONY: deps format compile test cli-cover-report html-cover-report @@ -16,6 +16,7 @@ all: format compile test deps: @go mod tidy + @go get -u @go build -buildmode=plugin -v $(DIR)... format: @@ -29,7 +30,7 @@ ifdef DEBUG else ifdef CONTAINER @$(GOARGS) go build $(GO_CONTAINER_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR) else - @$(GOARGS) go build $(GO_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAMEs) $(DIR) + @$(GOARGS) go build $(GO_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR) endif test: diff --git a/pkg/plugins/tls_interceptor/addr_utils.go b/plugins/tls_interceptor/addr_utils.go similarity index 100% rename from pkg/plugins/tls_interceptor/addr_utils.go rename to plugins/tls_interceptor/addr_utils.go diff --git a/pkg/plugins/tls_interceptor/addr_utils_test.go b/plugins/tls_interceptor/addr_utils_test.go similarity index 100% rename from pkg/plugins/tls_interceptor/addr_utils_test.go rename to plugins/tls_interceptor/addr_utils_test.go diff --git a/pkg/plugins/tls_interceptor/cert_store.go b/plugins/tls_interceptor/cert_store.go similarity index 100% rename from pkg/plugins/tls_interceptor/cert_store.go rename to plugins/tls_interceptor/cert_store.go diff --git a/pkg/plugins/tls_interceptor/cert_store_test.go b/plugins/tls_interceptor/cert_store_test.go similarity index 100% rename from pkg/plugins/tls_interceptor/cert_store_test.go rename to plugins/tls_interceptor/cert_store_test.go diff --git a/pkg/plugins/tls_interceptor/certs.go b/plugins/tls_interceptor/certs.go similarity index 100% rename from pkg/plugins/tls_interceptor/certs.go rename to plugins/tls_interceptor/certs.go diff --git a/pkg/plugins/tls_interceptor/certs_test.go b/plugins/tls_interceptor/certs_test.go similarity index 100% rename from pkg/plugins/tls_interceptor/certs_test.go rename to plugins/tls_interceptor/certs_test.go diff --git a/plugins/tls_interceptor/fake_main.go b/plugins/tls_interceptor/fake_main.go new file mode 100644 index 0000000..fa0b8bf --- /dev/null +++ b/plugins/tls_interceptor/fake_main.go @@ -0,0 +1,5 @@ +package main + +func main() { + panic("should not every be called") +} diff --git a/pkg/plugins/tls_interceptor/generate_ca_cmd.go b/plugins/tls_interceptor/generate_ca_cmd.go similarity index 100% rename from pkg/plugins/tls_interceptor/generate_ca_cmd.go rename to plugins/tls_interceptor/generate_ca_cmd.go diff --git a/plugins/tls_interceptor/go.mod b/plugins/tls_interceptor/go.mod new file mode 100644 index 0000000..9e5b537 --- /dev/null +++ b/plugins/tls_interceptor/go.mod @@ -0,0 +1,12 @@ +module github.com/baez90/inetmock/plugins/tls_interceptor + +go 1.14 + +require ( + github.com/baez90/inetmock v0.0.1 + github.com/spf13/cobra v1.0.0 + github.com/spf13/viper v1.6.3 + go.uber.org/zap v1.14.1 +) + +replace github.com/baez90/inetmock v0.0.1 => ../../ diff --git a/pkg/plugins/dns_mock/go.sum b/plugins/tls_interceptor/go.sum similarity index 92% rename from pkg/plugins/dns_mock/go.sum rename to plugins/tls_interceptor/go.sum index 5b7ca71..34c4685 100644 --- a/pkg/plugins/dns_mock/go.sum +++ b/plugins/tls_interceptor/go.sum @@ -21,7 +21,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -69,10 +68,7 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg= -github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -81,7 +77,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= @@ -110,23 +105,17 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= -github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -160,7 +149,6 @@ go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -175,13 +163,10 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -189,12 +174,9 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -220,7 +202,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ= gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -228,7 +209,6 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/plugins/tls_interceptor/init.go b/plugins/tls_interceptor/init.go similarity index 100% rename from pkg/plugins/tls_interceptor/init.go rename to plugins/tls_interceptor/init.go diff --git a/pkg/plugins/tls_interceptor/main.go b/plugins/tls_interceptor/main.go similarity index 100% rename from pkg/plugins/tls_interceptor/main.go rename to plugins/tls_interceptor/main.go diff --git a/pkg/plugins/tls_interceptor/protocol_options.go b/plugins/tls_interceptor/protocol_options.go similarity index 100% rename from pkg/plugins/tls_interceptor/protocol_options.go rename to plugins/tls_interceptor/protocol_options.go diff --git a/pkg/plugins/tls_interceptor/proxy.go b/plugins/tls_interceptor/proxy.go similarity index 100% rename from pkg/plugins/tls_interceptor/proxy.go rename to plugins/tls_interceptor/proxy.go diff --git a/pkg/plugins/tls_interceptor/proxy_conn.go b/plugins/tls_interceptor/proxy_conn.go similarity index 100% rename from pkg/plugins/tls_interceptor/proxy_conn.go rename to plugins/tls_interceptor/proxy_conn.go diff --git a/pkg/plugins/tls_interceptor/test_setup.go b/plugins/tls_interceptor/test_setup.go similarity index 100% rename from pkg/plugins/tls_interceptor/test_setup.go rename to plugins/tls_interceptor/test_setup.go diff --git a/pkg/plugins/tls_interceptor/time_source.go b/plugins/tls_interceptor/time_source.go similarity index 100% rename from pkg/plugins/tls_interceptor/time_source.go rename to plugins/tls_interceptor/time_source.go From 63a446d7e5a1b72609679ede2b32e25706d2c7f6 Mon Sep 17 00:00:00 2001 From: Peter Kurfer Date: Sat, 11 Apr 2020 23:29:52 +0200 Subject: [PATCH 3/9] Prepare systemd deployment - add systemd service - add default file - improve logging to see what kind of errors might occur - ship multiple prepared config files and replace original one with a symlink - fix current working directory getter --- config.yaml | 2 +- deploy/inetmock.default | 2 + deploy/inetmock.service | 15 ++++++ internal/cmd/init.go | 7 +++ internal/config/loading.go | 4 ++ internal/plugins/loading.go | 1 - mock_config.yaml | 95 +++++++++++++++++++++++++++++++++++++ pkg/path/helpers.go | 3 +- 8 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 deploy/inetmock.default create mode 100644 deploy/inetmock.service create mode 100644 mock_config.yaml diff --git a/config.yaml b/config.yaml index 723047e..2f94e96 100644 --- a/config.yaml +++ b/config.yaml @@ -52,7 +52,7 @@ endpoints: fallback: strategy: incremental args: - startIP: 10.0.0.0 + startIP: 10.0.10.0 dnsOverTlsDowngrade: handler: tls_interceptor listenAddress: 0.0.0.0 diff --git a/deploy/inetmock.default b/deploy/inetmock.default new file mode 100644 index 0000000..54b01bc --- /dev/null +++ b/deploy/inetmock.default @@ -0,0 +1,2 @@ +INETMOCK_PLUGINS_DIRECTORY=/usr/lib/inetmock/plugins +OPTIONS="--config=/etc/inetmock/config.yaml" \ No newline at end of file diff --git a/deploy/inetmock.service b/deploy/inetmock.service new file mode 100644 index 0000000..4a964ec --- /dev/null +++ b/deploy/inetmock.service @@ -0,0 +1,15 @@ +[Unit] +Description=INetMock is a simple service to simulate a valid internet connection + +[Service] +Type=simple +User=inetmock +AmbientCapabilities=CAP_NET_BIND_SERVICE +MemoryMax=50M +CPUQuota=20% +EnvironmentFile=/etc/default/inetmock +ExecStart=/usr/bin/inetmock $OPTIONS + WorkingDirectory=/var/lib/inetmock + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/internal/cmd/init.go b/internal/cmd/init.go index 478bc33..5a5d4e9 100644 --- a/internal/cmd/init.go +++ b/internal/cmd/init.go @@ -6,6 +6,7 @@ import ( "github.com/baez90/inetmock/pkg/path" "github.com/spf13/viper" "go.uber.org/zap" + "os" ) var ( @@ -24,6 +25,11 @@ func initApp() (err error) { ) logger, _ = logging.CreateLogger() registry := plugins.Registry() + + if err = rootCmd.ParseFlags(os.Args); err != nil { + return + } + if err = appConfig.ReadConfig(configFilePath); err != nil { logger.Error( "unrecoverable error occurred during reading the config file", @@ -36,6 +42,7 @@ func initApp() (err error) { pluginDir := viperInst.GetString("plugins-directory") if err = registry.LoadPlugins(pluginDir); err != nil { logger.Error("Failed to load plugins", + zap.String("pluginsDirectory", pluginDir), zap.Error(err), ) } diff --git a/internal/config/loading.go b/internal/config/loading.go index 32fd973..e699b82 100644 --- a/internal/config/loading.go +++ b/internal/config/loading.go @@ -39,6 +39,10 @@ func (c config) InitConfig(flags *pflag.FlagSet) { func (c *config) ReadConfig(configFilePath string) (err error) { if configFilePath != "" && path.FileExists(configFilePath) { + c.logger.Info( + "loading config from passed config file path", + zap.String("configFilePath", configFilePath), + ) viper.SetConfigFile(configFilePath) } if err = viper.ReadInConfig(); err != nil { diff --git a/internal/plugins/loading.go b/internal/plugins/loading.go index 73bb46a..1ef3ad7 100644 --- a/internal/plugins/loading.go +++ b/internal/plugins/loading.go @@ -56,7 +56,6 @@ func (h *handlerRegistry) RegisterHandler(handlerName string, handlerProvider ap } func (h *handlerRegistry) LoadPlugins(pluginsPath string) (err error) { - if !path.DirExists(pluginsPath) { err = fmt.Errorf("plugins path %s does not exist or is not accessible", pluginsPath) return diff --git a/mock_config.yaml b/mock_config.yaml new file mode 100644 index 0000000..deb5295 --- /dev/null +++ b/mock_config.yaml @@ -0,0 +1,95 @@ +endpoints: + plainHttp: + handler: http_mock + listenAddress: 0.0.0.0 + port: 80 + options: + rules: + - pattern: ".*\\.(?i)exe" + response: ./assets/fakeFiles/sample.exe + - pattern: ".*\\.(?i)(jpg|jpeg)" + response: ./assets/fakeFiles/default.jpg + - pattern: ".*\\.(?i)png" + response: ./assets/fakeFiles/default.png + - pattern: ".*\\.(?i)gif" + response: ./assets/fakeFiles/default.gif + - pattern: ".*\\.(?i)ico" + response: ./assets/fakeFiles/default.ico + - pattern: ".*\\.(?i)txt" + response: ./assets/fakeFiles/default.txt + - pattern: ".*" + response: ./assets/fakeFiles/default.html + proxy: + handler: http_proxy + listenAddress: 0.0.0.0 + port: 3128 + options: + rules: + - pattern: ".*\\.(?i)exe" + response: ./assets/fakeFiles/sample.exe + - pattern: ".*\\.(?i)(jpg|jpeg)" + response: ./assets/fakeFiles/default.jpg + - pattern: ".*\\.(?i)png" + response: ./assets/fakeFiles/default.png + - pattern: ".*\\.(?i)gif" + response: ./assets/fakeFiles/default.gif + - pattern: ".*\\.(?i)ico" + response: ./assets/fakeFiles/default.ico + - pattern: ".*\\.(?i)txt" + response: ./assets/fakeFiles/default.txt + - pattern: ".*" + response: ./assets/fakeFiles/default.html + httpsDowngrade: + handler: tls_interceptor + listenAddress: 0.0.0.0 + port: 443 + options: + ecdsaCurve: P256 + validity: + ca: + notBeforeRelative: 17520h + notAfterRelative: 17520h + domain: + notBeforeRelative: 168h + notAfterRelative: 168h + rootCaCert: + publicKey: ./ca.pem + privateKey: ./ca.key + certCachePath: /tmp/inetmock/ + target: + ipAddress: 127.0.0.1 + port: 80 + plainDns: + handler: dns_mock + listenAddress: 0.0.0.0 + port: 53 + options: + rules: + - pattern: ".*\\.google\\.com" + response: 1.1.1.1 + - pattern: ".*\\.reddit\\.com" + response: 2.2.2.2 + fallback: + strategy: incremental + args: + startIP: 10.0.10.0 + dnsOverTlsDowngrade: + handler: tls_interceptor + listenAddress: 0.0.0.0 + port: 853 + options: + ecdsaCurve: P256 + validity: + ca: + notBeforeRelative: 17520h + notAfterRelative: 17520h + domain: + notBeforeRelative: 168h + notAfterRelative: 168h + rootCaCert: + publicKey: ./ca.pem + privateKey: ./ca.key + certCachePath: /tmp/inetmock/ + target: + ipAddress: 127.0.0.1 + port: 53 \ No newline at end of file diff --git a/pkg/path/helpers.go b/pkg/path/helpers.go index 5ca4c62..c19d57c 100644 --- a/pkg/path/helpers.go +++ b/pkg/path/helpers.go @@ -2,11 +2,10 @@ package path import ( "os" - "path/filepath" ) func WorkingDirectory() (cwd string) { - cwd, _ = filepath.Abs(filepath.Dir(os.Args[0])) + cwd, _ = os.Getwd() return } From 671958e123e69e4f2e25e1dcd1c06e23083a3190 Mon Sep 17 00:00:00 2001 From: Peter Kurfer Date: Sun, 12 Apr 2020 03:51:41 +0200 Subject: [PATCH 4/9] Complete first naive HTTP proxy implementation - HTTPS configuration is till missing - fix a few minor things in other plugins - cleanup of config to reduce repeating of the same values multiple times --- Makefile | 8 ++- config.yaml | 76 +------------------- mock_config.yaml | 90 ++++++++++------------- plugins/dns_mock/Makefile | 6 +- plugins/dns_mock/fake_main.go | 5 -- plugins/dns_mock/main.go | 1 + plugins/http_mock/Makefile | 8 ++- plugins/http_mock/fake_main.go | 5 -- plugins/http_mock/http_handler.go | 37 ++++++++++ plugins/http_mock/main.go | 36 +--------- plugins/http_mock/protocol_options.go | 5 +- plugins/http_proxy/Makefile | 6 +- plugins/http_proxy/fake_main.go | 5 -- plugins/http_proxy/fallback.go | 53 ++++++++++++++ plugins/http_proxy/go.mod | 3 + plugins/http_proxy/go.sum | 9 +++ plugins/http_proxy/init.go | 10 +++ plugins/http_proxy/main.go | 42 +++++++++-- plugins/http_proxy/protocol_options.go | 52 ++++++++++++++ plugins/http_proxy/proxy_handler.go | 99 ++++++++++++++++++++++++++ plugins/tls_interceptor/Makefile | 6 +- plugins/tls_interceptor/fake_main.go | 5 -- plugins/tls_interceptor/main.go | 1 + proxy_config.yaml | 77 ++++++++++++++++++++ 24 files changed, 442 insertions(+), 203 deletions(-) mode change 100644 => 120000 config.yaml delete mode 100644 plugins/dns_mock/fake_main.go delete mode 100644 plugins/http_mock/fake_main.go create mode 100644 plugins/http_mock/http_handler.go delete mode 100644 plugins/http_proxy/fake_main.go create mode 100644 plugins/http_proxy/fallback.go create mode 100644 plugins/http_proxy/protocol_options.go create mode 100644 plugins/http_proxy/proxy_handler.go delete mode 100644 plugins/tls_interceptor/fake_main.go create mode 100644 proxy_config.yaml diff --git a/Makefile b/Makefile index b8ec306..66a0630 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ DEBUG_PORT = 2345 DEBUG_ARGS?= --development-logs=true INETMOCK_PLUGINS_DIRECTORY = $(DIR) -.PHONY: clean all format deps compile debug snapshot-release test cli-cover-report html-cover-report plugins $(PLUGINS) +.PHONY: clean all format deps update-deps compile debug snapshot-release test cli-cover-report html-cover-report plugins $(PLUGINS) all: clean format compile test plugins @@ -26,9 +26,11 @@ format: @go fmt $(PKGS) deps: + @go build -v $(BUILD_PATH) + +update-deps: @go mod tidy @go get -u - @go build -v $(BUILD_PATH) compile: deps ifdef DEBUG @@ -44,7 +46,7 @@ endif debug: @export INETMOCK_PLUGINS_DIRECTORY - @dlv exec $(DIR)$(BINARY_NAME) \ + dlv exec $(DIR)$(BINARY_NAME) \ --headless \ --listen=:2345 \ --api-version=2 \ diff --git a/config.yaml b/config.yaml deleted file mode 100644 index 2f94e96..0000000 --- a/config.yaml +++ /dev/null @@ -1,75 +0,0 @@ -endpoints: - plainHttp: - handler: http_mock - listenAddress: 0.0.0.0 - port: 80 - options: - rules: - - pattern: ".*\\.(?i)exe" - response: ./assets/fakeFiles/sample.exe - - pattern: ".*\\.(?i)(jpg|jpeg)" - response: ./assets/fakeFiles/default.jpg - - pattern: ".*\\.(?i)png" - response: ./assets/fakeFiles/default.png - - pattern: ".*\\.(?i)gif" - response: ./assets/fakeFiles/default.gif - - pattern: ".*\\.(?i)ico" - response: ./assets/fakeFiles/default.ico - - pattern: ".*\\.(?i)txt" - response: ./assets/fakeFiles/default.txt - - pattern: ".*" - response: ./assets/fakeFiles/default.html - httpsDowngrade: - handler: tls_interceptor - listenAddress: 0.0.0.0 - port: 443 - options: - ecdsaCurve: P256 - validity: - ca: - notBeforeRelative: 17520h - notAfterRelative: 17520h - domain: - notBeforeRelative: 168h - notAfterRelative: 168h - rootCaCert: - publicKey: ./ca.pem - privateKey: ./ca.key - certCachePath: /tmp/inetmock/ - target: - ipAddress: 127.0.0.1 - port: 80 - plainDns: - handler: dns_mock - listenAddress: 0.0.0.0 - port: 53 - options: - rules: - - pattern: ".*\\.google\\.com" - response: 1.1.1.1 - - pattern: ".*\\.reddit\\.com" - response: 2.2.2.2 - fallback: - strategy: incremental - args: - startIP: 10.0.10.0 - dnsOverTlsDowngrade: - handler: tls_interceptor - listenAddress: 0.0.0.0 - port: 853 - options: - ecdsaCurve: P256 - validity: - ca: - notBeforeRelative: 17520h - notAfterRelative: 17520h - domain: - notBeforeRelative: 168h - notAfterRelative: 168h - rootCaCert: - publicKey: ./ca.pem - privateKey: ./ca.key - certCachePath: /tmp/inetmock/ - target: - ipAddress: 127.0.0.1 - port: 53 \ No newline at end of file diff --git a/config.yaml b/config.yaml new file mode 120000 index 0000000..54eeef2 --- /dev/null +++ b/config.yaml @@ -0,0 +1 @@ +mock_config.yaml \ No newline at end of file diff --git a/mock_config.yaml b/mock_config.yaml index deb5295..450facc 100644 --- a/mock_config.yaml +++ b/mock_config.yaml @@ -1,61 +1,54 @@ +x-response-rules: &httpResponseRules + rules: + - pattern: ".*\\.(?i)exe" + response: ./assets/fakeFiles/sample.exe + - pattern: ".*\\.(?i)(jpg|jpeg)" + response: ./assets/fakeFiles/default.jpg + - pattern: ".*\\.(?i)png" + response: ./assets/fakeFiles/default.png + - pattern: ".*\\.(?i)gif" + response: ./assets/fakeFiles/default.gif + - pattern: ".*\\.(?i)ico" + response: ./assets/fakeFiles/default.ico + - pattern: ".*\\.(?i)txt" + response: ./assets/fakeFiles/default.txt + - pattern: ".*" + response: ./assets/fakeFiles/default.html + +x-tls-options: &tlsOptions + ecdsaCurve: P256 + validity: + ca: + notBeforeRelative: 17520h + notAfterRelative: 17520h + domain: + notBeforeRelative: 168h + notAfterRelative: 168h + rootCaCert: + publicKey: ./ca.pem + privateKey: ./ca.key + certCachePath: /tmp/inetmock/ + endpoints: plainHttp: handler: http_mock listenAddress: 0.0.0.0 port: 80 options: - rules: - - pattern: ".*\\.(?i)exe" - response: ./assets/fakeFiles/sample.exe - - pattern: ".*\\.(?i)(jpg|jpeg)" - response: ./assets/fakeFiles/default.jpg - - pattern: ".*\\.(?i)png" - response: ./assets/fakeFiles/default.png - - pattern: ".*\\.(?i)gif" - response: ./assets/fakeFiles/default.gif - - pattern: ".*\\.(?i)ico" - response: ./assets/fakeFiles/default.ico - - pattern: ".*\\.(?i)txt" - response: ./assets/fakeFiles/default.txt - - pattern: ".*" - response: ./assets/fakeFiles/default.html + <<: *httpResponseRules proxy: handler: http_proxy listenAddress: 0.0.0.0 port: 3128 options: - rules: - - pattern: ".*\\.(?i)exe" - response: ./assets/fakeFiles/sample.exe - - pattern: ".*\\.(?i)(jpg|jpeg)" - response: ./assets/fakeFiles/default.jpg - - pattern: ".*\\.(?i)png" - response: ./assets/fakeFiles/default.png - - pattern: ".*\\.(?i)gif" - response: ./assets/fakeFiles/default.gif - - pattern: ".*\\.(?i)ico" - response: ./assets/fakeFiles/default.ico - - pattern: ".*\\.(?i)txt" - response: ./assets/fakeFiles/default.txt - - pattern: ".*" - response: ./assets/fakeFiles/default.html + fallback: notfound + <<: *httpResponseRules httpsDowngrade: handler: tls_interceptor listenAddress: 0.0.0.0 port: 443 options: - ecdsaCurve: P256 - validity: - ca: - notBeforeRelative: 17520h - notAfterRelative: 17520h - domain: - notBeforeRelative: 168h - notAfterRelative: 168h - rootCaCert: - publicKey: ./ca.pem - privateKey: ./ca.key - certCachePath: /tmp/inetmock/ + <<: *tlsOptions target: ipAddress: 127.0.0.1 port: 80 @@ -78,18 +71,7 @@ endpoints: listenAddress: 0.0.0.0 port: 853 options: - ecdsaCurve: P256 - validity: - ca: - notBeforeRelative: 17520h - notAfterRelative: 17520h - domain: - notBeforeRelative: 168h - notAfterRelative: 168h - rootCaCert: - publicKey: ./ca.pem - privateKey: ./ca.key - certCachePath: /tmp/inetmock/ + <<: *tlsOptions target: ipAddress: 127.0.0.1 port: 53 \ No newline at end of file diff --git a/plugins/dns_mock/Makefile b/plugins/dns_mock/Makefile index 0086189..b9ad011 100644 --- a/plugins/dns_mock/Makefile +++ b/plugins/dns_mock/Makefile @@ -10,14 +10,16 @@ PLUGIN_NAME = $(shell basename $(DIR)).so OUT_DIR = $(DIR)../../ DEBUG_PORT = 2345 -.PHONY: deps format compile test cli-cover-report html-cover-report +.PHONY: deps update-deps format compile test cli-cover-report html-cover-report all: format compile test deps: + @go build -buildmode=plugin -v $(DIR)... + +update-deps: @go mod tidy @go get -u - @go build -buildmode=plugin -v $(DIR)... format: @go fmt $(PKGS) diff --git a/plugins/dns_mock/fake_main.go b/plugins/dns_mock/fake_main.go deleted file mode 100644 index fa0b8bf..0000000 --- a/plugins/dns_mock/fake_main.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -func main() { - panic("should not every be called") -} diff --git a/plugins/dns_mock/main.go b/plugins/dns_mock/main.go index 7171ee6..6e604e6 100644 --- a/plugins/dns_mock/main.go +++ b/plugins/dns_mock/main.go @@ -63,6 +63,7 @@ func (d *dnsHandler) startServer(dnsServer *dns.Server) { } func (d *dnsHandler) Shutdown(wg *sync.WaitGroup) { + d.logger.Info("shutting down DNS mock") for _, dnsServer := range d.dnsServer { if err := dnsServer.Shutdown(); err != nil { d.logger.Error( diff --git a/plugins/http_mock/Makefile b/plugins/http_mock/Makefile index ea47347..b9ad011 100644 --- a/plugins/http_mock/Makefile +++ b/plugins/http_mock/Makefile @@ -10,14 +10,16 @@ PLUGIN_NAME = $(shell basename $(DIR)).so OUT_DIR = $(DIR)../../ DEBUG_PORT = 2345 -.PHONY: deps format compile test cli-cover-report html-cover-report +.PHONY: deps update-deps format compile test cli-cover-report html-cover-report all: format compile test deps: + @go build -buildmode=plugin -v $(DIR)... + +update-deps: @go mod tidy @go get -u - @go build -buildmode=plugin -v $(DIR)... format: @go fmt $(PKGS) @@ -30,7 +32,7 @@ ifdef DEBUG else ifdef CONTAINER @$(GOARGS) go build $(GO_CONTAINER_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR) else - @$(GOARGS) go build $(GO_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAMEs) $(DIR) + @$(GOARGS) go build $(GO_BUILD_ARGS) -o $(OUT_DIR)/$(PLUGIN_NAME) $(DIR) endif test: diff --git a/plugins/http_mock/fake_main.go b/plugins/http_mock/fake_main.go deleted file mode 100644 index fa0b8bf..0000000 --- a/plugins/http_mock/fake_main.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -func main() { - panic("should not every be called") -} diff --git a/plugins/http_mock/http_handler.go b/plugins/http_mock/http_handler.go new file mode 100644 index 0000000..987c4d7 --- /dev/null +++ b/plugins/http_mock/http_handler.go @@ -0,0 +1,37 @@ +package main + +import ( + "bytes" + "go.uber.org/zap" + "net/http" +) + +func (p *httpHandler) setupRoute(rule targetRule) { + p.logger.Info( + "setup routing", + zap.String("route", rule.Pattern().String()), + zap.String("response", rule.Response()), + ) + + p.router.Handler(rule.Pattern(), createHandlerForTarget(p.logger, rule.response)) +} + +func createHandlerForTarget(logger *zap.Logger, targetPath string) http.Handler { + return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + headerWriter := &bytes.Buffer{} + request.Header.Write(headerWriter) + + logger.Info( + "Handling request", + zap.String("source", request.RemoteAddr), + zap.String("host", request.Host), + zap.String("method", request.Method), + zap.String("protocol", request.Proto), + zap.String("path", request.RequestURI), + zap.String("response", targetPath), + zap.Reflect("headers", request.Header), + ) + + http.ServeFile(writer, request, targetPath) + }) +} diff --git a/plugins/http_mock/main.go b/plugins/http_mock/main.go index 9ef13f9..5a5c1e1 100644 --- a/plugins/http_mock/main.go +++ b/plugins/http_mock/main.go @@ -1,13 +1,10 @@ package main import ( - "bytes" "fmt" "github.com/baez90/inetmock/internal/config" - "github.com/baez90/inetmock/pkg/path" "go.uber.org/zap" "net/http" - "path/filepath" "sync" ) @@ -37,6 +34,7 @@ func (p *httpHandler) Run(config config.HandlerConfig) { } func (p *httpHandler) Shutdown(wg *sync.WaitGroup) { + p.logger.Info("Shutting down HTTP mock") if err := p.server.Close(); err != nil { p.logger.Error( "failed to shutdown HTTP server", @@ -55,35 +53,3 @@ func (p *httpHandler) startServer() { ) } } - -func (p *httpHandler) setupRoute(rule targetRule) { - p.logger.Info( - "setup routing", - zap.String("route", rule.Pattern().String()), - zap.String("response", rule.Response()), - ) - - p.router.Handler(rule.Pattern(), createHandlerForTarget(p.logger, rule.response)) -} - -func createHandlerForTarget(logger *zap.Logger, targetPath string) http.Handler { - return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { - targetFilePath := filepath.Join(path.WorkingDirectory(), targetPath) - - headerWriter := &bytes.Buffer{} - request.Header.Write(headerWriter) - - logger.Info( - "Handling request", - zap.String("source", request.RemoteAddr), - zap.String("host", request.Host), - zap.String("method", request.Method), - zap.String("protocol", request.Proto), - zap.String("path", request.RequestURI), - zap.String("response", targetFilePath), - zap.Reflect("headers", request.Header), - ) - - http.ServeFile(writer, request, targetFilePath) - }) -} diff --git a/plugins/http_mock/protocol_options.go b/plugins/http_mock/protocol_options.go index 0c9f955..f4a5189 100644 --- a/plugins/http_mock/protocol_options.go +++ b/plugins/http_mock/protocol_options.go @@ -28,8 +28,7 @@ type httpOptions struct { Rules []targetRule } -func loadFromConfig(config *viper.Viper) httpOptions { - options := httpOptions{} +func loadFromConfig(config *viper.Viper) (options httpOptions) { anonRules := config.Get(rulesConfigKey).([]interface{}) for _, i := range anonRules { @@ -45,5 +44,5 @@ func loadFromConfig(config *viper.Viper) httpOptions { } } - return options + return } diff --git a/plugins/http_proxy/Makefile b/plugins/http_proxy/Makefile index 0086189..b9ad011 100644 --- a/plugins/http_proxy/Makefile +++ b/plugins/http_proxy/Makefile @@ -10,14 +10,16 @@ PLUGIN_NAME = $(shell basename $(DIR)).so OUT_DIR = $(DIR)../../ DEBUG_PORT = 2345 -.PHONY: deps format compile test cli-cover-report html-cover-report +.PHONY: deps update-deps format compile test cli-cover-report html-cover-report all: format compile test deps: + @go build -buildmode=plugin -v $(DIR)... + +update-deps: @go mod tidy @go get -u - @go build -buildmode=plugin -v $(DIR)... format: @go fmt $(PKGS) diff --git a/plugins/http_proxy/fake_main.go b/plugins/http_proxy/fake_main.go deleted file mode 100644 index fa0b8bf..0000000 --- a/plugins/http_proxy/fake_main.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -func main() { - panic("should not every be called") -} diff --git a/plugins/http_proxy/fallback.go b/plugins/http_proxy/fallback.go new file mode 100644 index 0000000..1a72564 --- /dev/null +++ b/plugins/http_proxy/fallback.go @@ -0,0 +1,53 @@ +package main + +import ( + "gopkg.in/elazarl/goproxy.v1" + "net/http" +) + +const ( + passthroughStrategyName = "passthrough" + notFoundStrategyName = "notfound" +) + +var ( + fallbackStrategies map[string]ProxyFallbackStrategy +) + +func init() { + fallbackStrategies = map[string]ProxyFallbackStrategy{ + passthroughStrategyName: &passthroughFallbackStrategy{}, + notFoundStrategyName: ¬FoundFallbackStrategy{}, + } +} + +func StrategyForName(name string) ProxyFallbackStrategy { + if strategy, ok := fallbackStrategies[name]; ok { + return strategy + } + return fallbackStrategies[notFoundStrategyName] +} + +type ProxyFallbackStrategy interface { + Apply(request *http.Request) (*http.Response, error) +} + +type passthroughFallbackStrategy struct { +} + +func (p passthroughFallbackStrategy) Apply(request *http.Request) (*http.Response, error) { + return nil, nil +} + +type notFoundFallbackStrategy struct { +} + +func (n notFoundFallbackStrategy) Apply(request *http.Request) (response *http.Response, err error) { + response = goproxy.NewResponse( + request, + goproxy.ContentTypeText, + http.StatusNotFound, + "The requested resource was not found", + ) + return +} diff --git a/plugins/http_proxy/go.mod b/plugins/http_proxy/go.mod index dc5e230..c592bcb 100644 --- a/plugins/http_proxy/go.mod +++ b/plugins/http_proxy/go.mod @@ -4,7 +4,10 @@ go 1.14 require ( github.com/baez90/inetmock v0.0.1 + github.com/elazarl/goproxy v0.0.0-20200315184450-1f3cb6622dad + github.com/spf13/viper v1.6.3 go.uber.org/zap v1.14.1 + gopkg.in/elazarl/goproxy.v1 v1.0.0-20180725130230-947c36da3153 ) replace github.com/baez90/inetmock v0.0.1 => ../../ diff --git a/plugins/http_proxy/go.sum b/plugins/http_proxy/go.sum index 5b68430..6397fa2 100644 --- a/plugins/http_proxy/go.sum +++ b/plugins/http_proxy/go.sum @@ -21,6 +21,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/elazarl/goproxy v0.0.0-20200315184450-1f3cb6622dad h1:zPs0fNF2Io1Qytf92EI2CDJ9oCXZr+NmjEVexrUEdq4= +github.com/elazarl/goproxy v0.0.0-20200315184450-1f3cb6622dad/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM= +github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -48,6 +52,7 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -94,6 +99,7 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -110,6 +116,7 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= @@ -199,6 +206,8 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/elazarl/goproxy.v1 v1.0.0-20180725130230-947c36da3153 h1:i2sumy6EgvN2dbX7HPhoDc7hLyoym3OYdU5HlvUUrpE= +gopkg.in/elazarl/goproxy.v1 v1.0.0-20180725130230-947c36da3153/go.mod h1:xzjpkyedLMz3EXUTBbkRuuGPsxfsBX3Sy7J6kC9Gvoc= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ= diff --git a/plugins/http_proxy/init.go b/plugins/http_proxy/init.go index 22ef15e..ea0d660 100644 --- a/plugins/http_proxy/init.go +++ b/plugins/http_proxy/init.go @@ -1,8 +1,11 @@ package main import ( + "github.com/baez90/inetmock/internal/plugins" + "github.com/baez90/inetmock/pkg/api" "github.com/baez90/inetmock/pkg/logging" "go.uber.org/zap" + "gopkg.in/elazarl/goproxy.v1" ) func init() { @@ -10,4 +13,11 @@ func init() { logger = logger.With( zap.String("ProtocolHandler", name), ) + + plugins.Registry().RegisterHandler(name, func() api.ProtocolHandler { + return &httpProxy{ + logger: logger, + proxy: goproxy.NewProxyHttpServer(), + } + }) } diff --git a/plugins/http_proxy/main.go b/plugins/http_proxy/main.go index 9b644a0..78bbab3 100644 --- a/plugins/http_proxy/main.go +++ b/plugins/http_proxy/main.go @@ -1,8 +1,11 @@ package main import ( + "fmt" "github.com/baez90/inetmock/internal/config" "go.uber.org/zap" + "gopkg.in/elazarl/goproxy.v1" + "net/http" "sync" ) @@ -12,12 +15,43 @@ const ( type httpProxy struct { logger *zap.Logger + proxy *goproxy.ProxyHttpServer + server *http.Server } -func (h httpProxy) Run(config config.HandlerConfig) { - panic("implement me") +func (h *httpProxy) Run(config config.HandlerConfig) { + options := loadFromConfig(config.Options()) + addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) + h.server = &http.Server{Addr: addr, Handler: h.proxy} + h.logger = h.logger.With( + zap.String("address", addr), + ) + + proxyHandler := &proxyHttpHandler{ + options: options, + logger: h.logger, + } + h.proxy.OnRequest().Do(proxyHandler) + h.proxy.OnRequest().HandleConnect() + go h.startProxy() } -func (h httpProxy) Shutdown(wg *sync.WaitGroup) { - panic("implement me") +func (h *httpProxy) startProxy() { + if err := h.server.ListenAndServe(); err != nil { + h.logger.Error( + "failed to start proxy server", + zap.Error(err), + ) + } +} + +func (h *httpProxy) Shutdown(wg *sync.WaitGroup) { + defer wg.Done() + h.logger.Info("Shutting down HTTP proxy") + if err := h.server.Close(); err != nil { + h.logger.Error( + "failed to shutdown proxy endpoint", + zap.Error(err), + ) + } } diff --git a/plugins/http_proxy/protocol_options.go b/plugins/http_proxy/protocol_options.go new file mode 100644 index 0000000..751c1ba --- /dev/null +++ b/plugins/http_proxy/protocol_options.go @@ -0,0 +1,52 @@ +package main + +import ( + "github.com/spf13/viper" + "regexp" +) + +const ( + rulesConfigKey = "rules" + patternConfigKey = "pattern" + responseConfigKey = "response" + fallbackStrategyConfigKey = "fallback" +) + +type targetRule struct { + pattern *regexp.Regexp + response string +} + +func (tr targetRule) Pattern() *regexp.Regexp { + return tr.pattern +} + +func (tr targetRule) Response() string { + return tr.response +} + +type httpProxyOptions struct { + Rules []targetRule + FallbackStrategy ProxyFallbackStrategy +} + +func loadFromConfig(config *viper.Viper) (options httpProxyOptions) { + options.FallbackStrategy = StrategyForName(config.GetString(fallbackStrategyConfigKey)) + + anonRules := config.Get(rulesConfigKey).([]interface{}) + + for _, i := range anonRules { + innerData := i.(map[interface{}]interface{}) + + if rulePattern, err := regexp.Compile(innerData[patternConfigKey].(string)); err == nil { + options.Rules = append(options.Rules, targetRule{ + pattern: rulePattern, + response: innerData[responseConfigKey].(string), + }) + } else { + panic(err) + } + } + + return +} diff --git a/plugins/http_proxy/proxy_handler.go b/plugins/http_proxy/proxy_handler.go new file mode 100644 index 0000000..b0a3798 --- /dev/null +++ b/plugins/http_proxy/proxy_handler.go @@ -0,0 +1,99 @@ +package main + +import ( + "go.uber.org/zap" + "gopkg.in/elazarl/goproxy.v1" + "io" + "mime" + "net/http" + "os" + "path/filepath" +) + +type proxyHttpHandler struct { + options httpProxyOptions + logger *zap.Logger +} + +/* +TODO implement HTTPS proxy like in TLS interceptor +func (p *proxyHttpHandler) HandleConnect(req string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) { + return &goproxy.ConnectAction{ + Action: goproxy.OkConnect, + + }, "" +}*/ + +func (p *proxyHttpHandler) Handle(req *http.Request, _ *goproxy.ProxyCtx) (retReq *http.Request, resp *http.Response) { + + retReq = req + resp = &http.Response{ + Request: req, + TransferEncoding: req.TransferEncoding, + Header: make(http.Header), + StatusCode: http.StatusOK, + } + + p.logger.Info( + "Handling request", + zap.String("source", req.RemoteAddr), + zap.String("host", req.Host), + zap.String("method", req.Method), + zap.String("protocol", req.Proto), + zap.String("path", req.RequestURI), + zap.Reflect("headers", req.Header), + ) + + for _, rule := range p.options.Rules { + if rule.pattern.MatchString(req.URL.Path) { + if file, err := os.Open(rule.response); err != nil { + p.logger.Error( + "failed to open response target file", + zap.String("resonse", rule.response), + zap.Error(err), + ) + continue + } else { + resp.Body = file + + if stat, err := file.Stat(); err == nil { + resp.ContentLength = stat.Size() + } + + if contentType, err := GetContentType(rule, file); err == nil { + resp.Header["Content-Type"] = []string{contentType} + } + + p.logger.Info("returning fake response from rules") + return req, resp + } + } + } + + if resp, err := p.options.FallbackStrategy.Apply(req); err != nil { + p.logger.Error( + "failed to apply fallback strategy", + zap.Error(err), + ) + } else { + p.logger.Info("returning fake response from fallback strategy") + return req, resp + } + + p.logger.Info("falling back to proxying request through") + return req, nil +} + +func GetContentType(rule targetRule, file *os.File) (contentType string, err error) { + if contentType = mime.TypeByExtension(filepath.Ext(rule.response)); contentType != "" { + return + } + + var buf [512]byte + + n, _ := io.ReadFull(file, buf[:]) + + contentType = http.DetectContentType(buf[:n]) + _, err = file.Seek(0, io.SeekStart) + return +} diff --git a/plugins/tls_interceptor/Makefile b/plugins/tls_interceptor/Makefile index 0086189..b9ad011 100644 --- a/plugins/tls_interceptor/Makefile +++ b/plugins/tls_interceptor/Makefile @@ -10,14 +10,16 @@ PLUGIN_NAME = $(shell basename $(DIR)).so OUT_DIR = $(DIR)../../ DEBUG_PORT = 2345 -.PHONY: deps format compile test cli-cover-report html-cover-report +.PHONY: deps update-deps format compile test cli-cover-report html-cover-report all: format compile test deps: + @go build -buildmode=plugin -v $(DIR)... + +update-deps: @go mod tidy @go get -u - @go build -buildmode=plugin -v $(DIR)... format: @go fmt $(PKGS) diff --git a/plugins/tls_interceptor/fake_main.go b/plugins/tls_interceptor/fake_main.go deleted file mode 100644 index fa0b8bf..0000000 --- a/plugins/tls_interceptor/fake_main.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -func main() { - panic("should not every be called") -} diff --git a/plugins/tls_interceptor/main.go b/plugins/tls_interceptor/main.go index 0ec98d9..3d6cf40 100644 --- a/plugins/tls_interceptor/main.go +++ b/plugins/tls_interceptor/main.go @@ -68,6 +68,7 @@ func (t *tlsInterceptor) Run(config config.HandlerConfig) { } func (t *tlsInterceptor) Shutdown(wg *sync.WaitGroup) { + t.logger.Info("Shutting down TLS interceptor") t.shutdownRequested = true done := make(chan struct{}) go func() { diff --git a/proxy_config.yaml b/proxy_config.yaml new file mode 100644 index 0000000..7c3b15d --- /dev/null +++ b/proxy_config.yaml @@ -0,0 +1,77 @@ +endpoints: + plainHttp: + handler: http_proxy + listenAddress: 0.0.0.0 + port: 80 + options: + rules: + - pattern: ".*\\.(?i)exe" + response: ./assets/fakeFiles/sample.exe + - pattern: ".*\\.(?i)(jpg|jpeg)" + response: ./assets/fakeFiles/default.jpg + - pattern: ".*\\.(?i)png" + response: ./assets/fakeFiles/default.png + - pattern: ".*\\.(?i)gif" + response: ./assets/fakeFiles/default.gif + - pattern: ".*\\.(?i)ico" + response: ./assets/fakeFiles/default.ico + - pattern: ".*\\.(?i)txt" + response: ./assets/fakeFiles/default.txt + - pattern: ".*" + response: ./assets/fakeFiles/default.html + httpsDowngrade: + handler: tls_interceptor + listenAddress: 0.0.0.0 + port: 443 + options: + ecdsaCurve: P256 + validity: + ca: + notBeforeRelative: 17520h + notAfterRelative: 17520h + domain: + notBeforeRelative: 168h + notAfterRelative: 168h + rootCaCert: + publicKey: ./ca.pem + privateKey: ./ca.key + certCachePath: /tmp/inetmock/ + target: + ipAddress: 127.0.0.1 + port: 80 + plainDns: + handler: dns_mock + listenAddress: 0.0.0.0 + port: 53 + options: + rules: + - pattern: "www.golem.de" + response: 77.247.84.129 + - pattern: ".*\\.google\\.com" + response: 1.1.1.1 + - pattern: ".*\\.reddit\\.com" + response: 2.2.2.2 + fallback: + strategy: incremental + args: + startIP: 10.0.0.0 + dnsOverTlsDowngrade: + handler: tls_interceptor + listenAddress: 0.0.0.0 + port: 853 + options: + ecdsaCurve: P256 + validity: + ca: + notBeforeRelative: 17520h + notAfterRelative: 17520h + domain: + notBeforeRelative: 168h + notAfterRelative: 168h + rootCaCert: + publicKey: ./ca.pem + privateKey: ./ca.key + certCachePath: /tmp/inetmock/ + target: + ipAddress: 127.0.0.1 + port: 53 \ No newline at end of file From f4ca8e91f2d3853e2bfc62e7c4450a07b4129326 Mon Sep 17 00:00:00 2001 From: Peter Kurfer Date: Sun, 12 Apr 2020 17:09:50 +0200 Subject: [PATCH 5/9] Add some tests to ensure proper configuration parsing --- internal/cmd/root.go | 2 +- pkg/api/protocol_handler.go | 2 +- plugins/dns_mock/main.go | 2 +- plugins/http_mock/main.go | 2 +- plugins/http_proxy/fallback.go | 6 +- plugins/http_proxy/fallback_test.go | 46 +++++++ plugins/http_proxy/main.go | 3 +- plugins/http_proxy/protocol_options_test.go | 126 ++++++++++++++++++++ plugins/tls_interceptor/main.go | 2 +- 9 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 plugins/http_proxy/fallback_test.go create mode 100644 plugins/http_proxy/protocol_options_test.go diff --git a/internal/cmd/root.go b/internal/cmd/root.go index ae5f2c6..293db28 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -88,7 +88,7 @@ func startEndpoint(handler api.ProtocolHandler, config config.HandlerConfig, log ) } }() - handler.Run(config) + handler.Start(config) } func shutdownEndpoint(handler api.ProtocolHandler, wg *sync.WaitGroup, logger *zap.Logger) { diff --git a/pkg/api/protocol_handler.go b/pkg/api/protocol_handler.go index 98c2aa2..5b3607a 100644 --- a/pkg/api/protocol_handler.go +++ b/pkg/api/protocol_handler.go @@ -11,6 +11,6 @@ type PluginInstanceFactory func() ProtocolHandler type LoggingFactory func() (*zap.Logger, error) type ProtocolHandler interface { - Run(config config.HandlerConfig) + Start(config config.HandlerConfig) Shutdown(wg *sync.WaitGroup) } diff --git a/plugins/dns_mock/main.go b/plugins/dns_mock/main.go index 6e604e6..27f30b6 100644 --- a/plugins/dns_mock/main.go +++ b/plugins/dns_mock/main.go @@ -13,7 +13,7 @@ type dnsHandler struct { dnsServer []*dns.Server } -func (d *dnsHandler) Run(config config.HandlerConfig) { +func (d *dnsHandler) Start(config config.HandlerConfig) { options := loadFromConfig(config.Options()) addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) diff --git a/plugins/http_mock/main.go b/plugins/http_mock/main.go index 5a5c1e1..6f586a2 100644 --- a/plugins/http_mock/main.go +++ b/plugins/http_mock/main.go @@ -18,7 +18,7 @@ type httpHandler struct { server *http.Server } -func (p *httpHandler) Run(config config.HandlerConfig) { +func (p *httpHandler) Start(config config.HandlerConfig) { options := loadFromConfig(config.Options()) addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) p.server = &http.Server{Addr: addr, Handler: p.router} diff --git a/plugins/http_proxy/fallback.go b/plugins/http_proxy/fallback.go index 1a72564..6cd87f4 100644 --- a/plugins/http_proxy/fallback.go +++ b/plugins/http_proxy/fallback.go @@ -16,7 +16,7 @@ var ( func init() { fallbackStrategies = map[string]ProxyFallbackStrategy{ - passthroughStrategyName: &passthroughFallbackStrategy{}, + passthroughStrategyName: &passThroughFallbackStrategy{}, notFoundStrategyName: ¬FoundFallbackStrategy{}, } } @@ -32,10 +32,10 @@ type ProxyFallbackStrategy interface { Apply(request *http.Request) (*http.Response, error) } -type passthroughFallbackStrategy struct { +type passThroughFallbackStrategy struct { } -func (p passthroughFallbackStrategy) Apply(request *http.Request) (*http.Response, error) { +func (p passThroughFallbackStrategy) Apply(request *http.Request) (*http.Response, error) { return nil, nil } diff --git a/plugins/http_proxy/fallback_test.go b/plugins/http_proxy/fallback_test.go new file mode 100644 index 0000000..09bf015 --- /dev/null +++ b/plugins/http_proxy/fallback_test.go @@ -0,0 +1,46 @@ +package main + +import ( + "reflect" + "testing" +) + +func TestStrategyForName(t *testing.T) { + type args struct { + name string + } + tests := []struct { + name string + args args + want reflect.Type + }{ + { + name: "Test get notfound strategy", + want: reflect.TypeOf(¬FoundFallbackStrategy{}), + args: args{ + name: "notfound", + }, + }, + { + name: "Test get pass through strategy", + want: reflect.TypeOf(&passThroughFallbackStrategy{}), + args: args{ + name: "passthrough", + }, + }, + { + name: "Test get fallback strategy notfound because key is not known", + want: reflect.TypeOf(¬FoundFallbackStrategy{}), + args: args{ + name: "asdf12234", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := StrategyForName(tt.args.name); reflect.TypeOf(got) != tt.want { + t.Errorf("StrategyForName() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/plugins/http_proxy/main.go b/plugins/http_proxy/main.go index 78bbab3..08b5496 100644 --- a/plugins/http_proxy/main.go +++ b/plugins/http_proxy/main.go @@ -19,7 +19,7 @@ type httpProxy struct { server *http.Server } -func (h *httpProxy) Run(config config.HandlerConfig) { +func (h *httpProxy) Start(config config.HandlerConfig) { options := loadFromConfig(config.Options()) addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) h.server = &http.Server{Addr: addr, Handler: h.proxy} @@ -32,7 +32,6 @@ func (h *httpProxy) Run(config config.HandlerConfig) { logger: h.logger, } h.proxy.OnRequest().Do(proxyHandler) - h.proxy.OnRequest().HandleConnect() go h.startProxy() } diff --git a/plugins/http_proxy/protocol_options_test.go b/plugins/http_proxy/protocol_options_test.go new file mode 100644 index 0000000..b706998 --- /dev/null +++ b/plugins/http_proxy/protocol_options_test.go @@ -0,0 +1,126 @@ +package main + +import ( + "bytes" + "github.com/spf13/viper" + "reflect" + "regexp" + "testing" +) + +func Test_loadFromConfig(t *testing.T) { + type args struct { + config string + } + tests := []struct { + name string + args args + wantOptions httpProxyOptions + }{ + { + name: "Parse proper configuration with notfound strategy", + args: args{ + config: ` +fallback: notfound, +rules: + - pattern: ".*" + response: ./assets/fakeFiles/default.html +`, + }, + wantOptions: httpProxyOptions{ + FallbackStrategy: StrategyForName(notFoundStrategyName), + Rules: []targetRule{ + { + response: "./assets/fakeFiles/default.html", + pattern: regexp.MustCompile(".*"), + }, + }, + }, + }, + { + name: "Parse proper configuration with pass through strategy", + args: args{ + config: ` +fallback: passthrough +rules: + - pattern: ".*" + response: ./assets/fakeFiles/default.html +`, + }, + wantOptions: httpProxyOptions{ + FallbackStrategy: StrategyForName(passthroughStrategyName), + Rules: []targetRule{ + { + response: "./assets/fakeFiles/default.html", + pattern: regexp.MustCompile(".*"), + }, + }, + }, + }, + { + name: "Parse proper configuration and preserve order of rules", + args: args{ + config: ` +fallback: notfound +rules: + - pattern: ".*\\.(?i)txt" + response: ./assets/fakeFiles/default.txt + - pattern: ".*" + response: ./assets/fakeFiles/default.html +`, + }, + wantOptions: httpProxyOptions{ + FallbackStrategy: StrategyForName(notFoundStrategyName), + Rules: []targetRule{ + { + response: "./assets/fakeFiles/default.txt", + pattern: regexp.MustCompile(".*\\.(?i)txt"), + }, + { + response: "./assets/fakeFiles/default.html", + pattern: regexp.MustCompile(".*"), + }, + }, + }, + }, + { + name: "Parse configuration with non existing fallback strategy key - falling back to 'notfound'", + args: args{ + config: ` +fallback: doesNotExist +rules: [] +`, + }, + wantOptions: httpProxyOptions{ + FallbackStrategy: StrategyForName(notFoundStrategyName), + Rules: nil, + }, + }, + { + name: "Parse configuration without any fallback key", + args: args{ + config: ` +f4llb4ck: doesNotExist +rules: [] +`, + }, + wantOptions: httpProxyOptions{ + FallbackStrategy: StrategyForName(notFoundStrategyName), + Rules: nil, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + config := viper.New() + config.SetConfigType("yaml") + if err := config.ReadConfig(bytes.NewBufferString(tt.args.config)); err != nil { + t.Errorf("failed to read config %v", err) + return + } + if gotOptions := loadFromConfig(config); !reflect.DeepEqual(gotOptions, tt.wantOptions) { + t.Errorf("loadFromConfig() = %v, want %v", gotOptions, tt.wantOptions) + } + }) + } +} diff --git a/plugins/tls_interceptor/main.go b/plugins/tls_interceptor/main.go index 3d6cf40..24af7d3 100644 --- a/plugins/tls_interceptor/main.go +++ b/plugins/tls_interceptor/main.go @@ -25,7 +25,7 @@ type tlsInterceptor struct { currentConnections []*proxyConn } -func (t *tlsInterceptor) Run(config config.HandlerConfig) { +func (t *tlsInterceptor) Start(config config.HandlerConfig) { var err error t.options = loadFromConfig(config.Options()) addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) From 9236a38be0e879c83d0236a74be79659f2201369 Mon Sep 17 00:00:00 2001 From: Peter Kurfer Date: Tue, 14 Apr 2020 00:14:56 +0200 Subject: [PATCH 6/9] Moved endpoint handling to new module - introduce new endpoints module - introduce Endpoint and EndpointManager - introduce new Logging abstraction API to allow proper mocking - add error return value to Start and Shutdown of endpoints - add mocks of some internals to allow easier testing - add generate target to take care of all code generation --- .goreleaser.yml | 2 +- Makefile | 14 +- go.mod | 1 + go.sum | 7 + internal/cmd/init.go | 9 + internal/cmd/root.go | 64 ++--- internal/config/handler_config.go | 40 ++-- internal/config/handler_config_test.go | 167 +++++++++++++ internal/config/loading.go | 2 +- internal/config/multi_handler_config.go | 48 ++++ internal/config/multi_handler_config_test.go | 240 +++++++++++++++++++ internal/config/parsing.go | 26 ++ internal/config/parsing_test.go | 145 +++++++++++ internal/endpoints/endpoint.go | 31 +++ internal/endpoints/endpoint_manager.go | 130 ++++++++++ internal/endpoints/endpoint_manager_test.go | 116 +++++++++ internal/endpoints/endpoint_test.go | 179 ++++++++++++++ internal/plugins/loading.go | 3 +- internal/plugins/loading_test.go | 109 +++++++++ mock_config.yaml | 8 +- pkg/api/protocol_handler.go | 6 +- pkg/logging/factory.go | 12 +- pkg/logging/factory_test.go | 166 +++++++++++++ pkg/logging/logger.go | 60 +++++ plugins/dns_mock/go.sum | 5 + plugins/dns_mock/main.go | 11 +- plugins/dns_mock/regex_handler.go | 3 +- plugins/http_mock/go.sum | 5 + plugins/http_mock/http_handler.go | 3 +- plugins/http_mock/main.go | 18 +- plugins/http_proxy/go.sum | 5 + plugins/http_proxy/main.go | 18 +- plugins/http_proxy/proxy_handler.go | 3 +- plugins/tls_interceptor/cert_store.go | 3 +- plugins/tls_interceptor/cert_store_test.go | 4 +- plugins/tls_interceptor/generate_ca_cmd.go | 9 +- plugins/tls_interceptor/go.sum | 5 + plugins/tls_interceptor/main.go | 28 ++- 38 files changed, 1586 insertions(+), 119 deletions(-) create mode 100644 internal/config/handler_config_test.go create mode 100644 internal/config/multi_handler_config.go create mode 100644 internal/config/multi_handler_config_test.go create mode 100644 internal/config/parsing.go create mode 100644 internal/config/parsing_test.go create mode 100644 internal/endpoints/endpoint.go create mode 100644 internal/endpoints/endpoint_manager.go create mode 100644 internal/endpoints/endpoint_manager_test.go create mode 100644 internal/endpoints/endpoint_test.go create mode 100644 internal/plugins/loading_test.go create mode 100644 pkg/logging/factory_test.go create mode 100644 pkg/logging/logger.go diff --git a/.goreleaser.yml b/.goreleaser.yml index dad29e5..2f81f84 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -3,7 +3,7 @@ before: hooks: # You may remove this if you don't use go modules. - - make plugins + - make handlers builds: - id: "default" ldflags: diff --git a/Makefile b/Makefile index 66a0630..46debe7 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ DIR = $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) BUILD_PATH = $(DIR)/main.go PKGS = $(shell go list ./...) TEST_PKGS = $(shell find . -type f -name "*_test.go" -not -path "./plugins/*" -printf '%h\n' | sort -u) +GO_GEN_FILES = $(shell grep -rnwl --include="*.go" "go:generate" $(DIR)) GOARGS = GOOS=linux GOARCH=amd64 GO_BUILD_ARGS = -ldflags="-w -s" GO_CONTAINER_BUILD_ARGS = -ldflags="-w -s" -a -installsuffix cgo @@ -11,10 +12,8 @@ BINARY_NAME = inetmock PLUGINS = $(wildcard $(DIR)plugins/*/.) DEBUG_PORT = 2345 DEBUG_ARGS?= --development-logs=true -INETMOCK_PLUGINS_DIRECTORY = $(DIR) - -.PHONY: clean all format deps update-deps compile debug snapshot-release test cli-cover-report html-cover-report plugins $(PLUGINS) +.PHONY: clean all format deps update-deps compile debug generate snapshot-release test cli-cover-report html-cover-report plugins $(PLUGINS) $(.PHONY: clean all format deps update-deps compile debug generate snapshot-release test cli-cover-report html-cover-report plugins $(PLUGINS) $(GO_GEN_FILES) all: clean format compile test plugins clean: @@ -44,8 +43,8 @@ else @$(GOARGS) go build $(GO_BUILD_ARGS) -o $(DIR)$(BINARY_NAME) $(BUILD_PATH) endif +debug: export INETMOCK_PLUGINS_DIRECTORY = $(DIR) debug: - @export INETMOCK_PLUGINS_DIRECTORY dlv exec $(DIR)$(BINARY_NAME) \ --headless \ --listen=:2345 \ @@ -53,6 +52,11 @@ debug: --accept-multiclient \ -- $(DEBUG_ARGS) +generate: + @for go_gen_target in $(GO_GEN_FILES); do \ + go generate $$go_gen_target; \ + done + snapshot-release: @goreleaser release --snapshot --skip-publish --rm-dist @@ -63,7 +67,7 @@ test: cli-cover-report: @go tool cover -func=cov.out -html-cover-report: +html-cover-report: test @go tool cover -html=cov.out -o .coverage.html plugins: $(PLUGINS) diff --git a/go.mod b/go.mod index 1cd0e7c..c8d8d9d 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.13 require ( github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/golang/mock v1.4.3 github.com/mitchellh/mapstructure v1.2.2 // indirect github.com/pelletier/go-toml v1.7.0 // indirect github.com/spf13/afero v1.2.2 // indirect diff --git a/go.sum b/go.sum index 34c4685..36f19f8 100644 --- a/go.sum +++ b/go.sum @@ -33,7 +33,10 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1 h1:G5FRp8JnTd7RQH5kemVNlMeyXQAztQ3mOWV95KxsXH8= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -177,6 +180,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -186,6 +190,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -215,3 +220,5 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/internal/cmd/init.go b/internal/cmd/init.go index 5a5d4e9..eb8494a 100644 --- a/internal/cmd/init.go +++ b/internal/cmd/init.go @@ -1,12 +1,14 @@ package cmd import ( + "github.com/baez90/inetmock/internal/endpoints" "github.com/baez90/inetmock/internal/plugins" "github.com/baez90/inetmock/pkg/logging" "github.com/baez90/inetmock/pkg/path" "github.com/spf13/viper" "go.uber.org/zap" "os" + "time" ) var ( @@ -25,6 +27,7 @@ func initApp() (err error) { ) logger, _ = logging.CreateLogger() registry := plugins.Registry() + endpointManager = endpoints.NewEndpointManager(logger) if err = rootCmd.ParseFlags(os.Args); err != nil { return @@ -40,12 +43,18 @@ func initApp() (err error) { viperInst := viper.GetViper() pluginDir := viperInst.GetString("plugins-directory") + pluginLoadStartTime := time.Now() if err = registry.LoadPlugins(pluginDir); err != nil { logger.Error("Failed to load plugins", zap.String("pluginsDirectory", pluginDir), zap.Error(err), ) } + pluginLoadDuration := time.Since(pluginLoadStartTime) + logger.Info( + "loading plugins completed", + zap.Duration("pluginLoadDuration", pluginLoadDuration), + ) pluginsCmd.AddCommand(registry.PluginCommands()...) diff --git a/internal/cmd/root.go b/internal/cmd/root.go index 293db28..bdab14b 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -2,20 +2,20 @@ package cmd import ( "github.com/baez90/inetmock/internal/config" - "github.com/baez90/inetmock/internal/plugins" + "github.com/baez90/inetmock/internal/endpoints" "github.com/baez90/inetmock/pkg/api" + "github.com/baez90/inetmock/pkg/logging" "github.com/spf13/cobra" "github.com/spf13/viper" "go.uber.org/zap" "os" "os/signal" "strings" - "sync" "syscall" ) var ( - logger *zap.Logger + logger logging.Logger rootCmd = cobra.Command{ Use: "", Short: "INetMock is lightweight internet mock", @@ -27,6 +27,7 @@ var ( developmentLogs bool handlers []api.ProtocolHandler appConfig = config.CreateConfig() + endpointManager endpoints.EndpointManager ) func init() { @@ -39,28 +40,21 @@ func init() { } func startInetMock(cmd *cobra.Command, args []string) { - registry := plugins.Registry() - var wg sync.WaitGroup - - //todo introduce endpoint type and move startup and shutdown to this type - - for key, val := range viper.GetStringMap(config.EndpointsKey) { - handlerSubConfig := viper.Sub(strings.Join([]string{config.EndpointsKey, key, config.OptionsKey}, ".")) - pluginConfig := config.CreateHandlerConfig(val, handlerSubConfig) - logger.Info(key, zap.Any("value", pluginConfig)) - - if handler, ok := registry.HandlerForName(pluginConfig.HandlerName()); ok { - handlers = append(handlers, handler) - go startEndpoint(handler, pluginConfig, logger) - wg.Add(1) - } else { + for endpointName := range viper.GetStringMap(config.EndpointsKey) { + handlerSubConfig := viper.Sub(strings.Join([]string{config.EndpointsKey, endpointName}, ".")) + handlerConfig := config.CreateMultiHandlerConfig(handlerSubConfig) + if err := endpointManager.CreateEndpoint(endpointName, handlerConfig); err != nil { logger.Warn( - "no matching handler registered", - zap.String("handler", pluginConfig.HandlerName()), + "error occurred while creating endpoint", + zap.String("endpointName", endpointName), + zap.String("handlerName", handlerConfig.HandlerName()), + zap.Error(err), ) } } + endpointManager.StartEndpoints() + signalChannel := make(chan os.Signal, 1) signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) @@ -72,35 +66,7 @@ func startInetMock(cmd *cobra.Command, args []string) { zap.String("signal", s.String()), ) - for _, handler := range handlers { - go shutdownEndpoint(handler, &wg, logger) - } - - wg.Wait() -} - -func startEndpoint(handler api.ProtocolHandler, config config.HandlerConfig, logger *zap.Logger) { - defer func() { - if r := recover(); r != nil { - logger.Fatal( - "recovered panic during startup of endpoint", - zap.Any("recovered", r), - ) - } - }() - handler.Start(config) -} - -func shutdownEndpoint(handler api.ProtocolHandler, wg *sync.WaitGroup, logger *zap.Logger) { - defer func() { - if r := recover(); r != nil { - logger.Fatal( - "recovered panic during shutdown of endpoint", - zap.Any("recovered", r), - ) - } - }() - handler.Shutdown(wg) + endpointManager.ShutdownEndpoints() } func ExecuteRootCommand() error { diff --git a/internal/config/handler_config.go b/internal/config/handler_config.go index 27bf5a3..cfeee30 100644 --- a/internal/config/handler_config.go +++ b/internal/config/handler_config.go @@ -4,19 +4,36 @@ import "github.com/spf13/viper" const ( pluginConfigKey = "handler" - listenAddressConfigKey = "listenaddress" + listenAddressConfigKey = "listenAddress" portConfigKey = "port" + portsConfigKey = "ports" ) +type HandlerConfig interface { + HandlerName() string + ListenAddress() string + Port() uint16 + Options() *viper.Viper +} + +func NewHandlerConfig(handlerName string, port uint16, listenAddress string, options *viper.Viper) HandlerConfig { + return &handlerConfig{ + handlerName: handlerName, + port: port, + listenAddress: listenAddress, + options: options, + } +} + type handlerConfig struct { - pluginName string + handlerName string port uint16 listenAddress string options *viper.Viper } func (h handlerConfig) HandlerName() string { - return h.pluginName + return h.handlerName } func (h handlerConfig) ListenAddress() string { @@ -30,20 +47,3 @@ func (h handlerConfig) Port() uint16 { func (h handlerConfig) Options() *viper.Viper { return h.options } - -type HandlerConfig interface { - HandlerName() string - ListenAddress() string - Port() uint16 - Options() *viper.Viper -} - -func CreateHandlerConfig(configMap interface{}, subConfig *viper.Viper) HandlerConfig { - underlyingMap := configMap.(map[string]interface{}) - return &handlerConfig{ - pluginName: underlyingMap[pluginConfigKey].(string), - listenAddress: underlyingMap[listenAddressConfigKey].(string), - port: uint16(underlyingMap[portConfigKey].(int)), - options: subConfig, - } -} diff --git a/internal/config/handler_config_test.go b/internal/config/handler_config_test.go new file mode 100644 index 0000000..838c5fd --- /dev/null +++ b/internal/config/handler_config_test.go @@ -0,0 +1,167 @@ +package config + +import ( + "github.com/spf13/viper" + "reflect" + "testing" +) + +func Test_handlerConfig_HandlerName(t *testing.T) { + type fields struct { + handlerName string + port uint16 + listenAddress string + options *viper.Viper + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "Get empty HandlerName for uninitialized struct", + fields: fields{}, + want: "", + }, + { + name: "Get expected HandlerName for initialized struct", + fields: fields{ + handlerName: "sampleHandler", + }, + want: "sampleHandler", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h := handlerConfig{ + handlerName: tt.fields.handlerName, + port: tt.fields.port, + listenAddress: tt.fields.listenAddress, + options: tt.fields.options, + } + if got := h.HandlerName(); got != tt.want { + t.Errorf("HandlerName() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_handlerConfig_ListenAddress(t *testing.T) { + type fields struct { + handlerName string + port uint16 + listenAddress string + options *viper.Viper + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "Get empty ListenAddress for uninitialized struct", + fields: fields{}, + want: "", + }, + { + name: "Get expected ListenAddress for initialized struct", + fields: fields{ + listenAddress: "0.0.0.0", + }, + want: "0.0.0.0", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h := handlerConfig{ + handlerName: tt.fields.handlerName, + port: tt.fields.port, + listenAddress: tt.fields.listenAddress, + options: tt.fields.options, + } + if got := h.ListenAddress(); got != tt.want { + t.Errorf("ListenAddress() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_handlerConfig_Options(t *testing.T) { + type fields struct { + handlerName string + port uint16 + listenAddress string + options *viper.Viper + } + tests := []struct { + name string + fields fields + want *viper.Viper + }{ + { + name: "Get nil Options for uninitialized struct", + fields: fields{}, + want: nil, + }, + { + name: "Get expected Options for initialized struct", + fields: fields{ + options: viper.New(), + }, + want: viper.New(), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h := handlerConfig{ + handlerName: tt.fields.handlerName, + port: tt.fields.port, + listenAddress: tt.fields.listenAddress, + options: tt.fields.options, + } + if got := h.Options(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Options() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_handlerConfig_Port(t *testing.T) { + type fields struct { + handlerName string + port uint16 + listenAddress string + options *viper.Viper + } + tests := []struct { + name string + fields fields + want uint16 + }{ + { + name: "Get empty Port for uninitialized struct", + fields: fields{}, + want: 0, + }, + { + name: "Get expected Port for initialized struct", + fields: fields{ + port: 80, + }, + want: 80, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h := handlerConfig{ + handlerName: tt.fields.handlerName, + port: tt.fields.port, + listenAddress: tt.fields.listenAddress, + options: tt.fields.options, + } + if got := h.Port(); got != tt.want { + t.Errorf("Port() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/config/loading.go b/internal/config/loading.go index e699b82..c0b1a03 100644 --- a/internal/config/loading.go +++ b/internal/config/loading.go @@ -22,7 +22,7 @@ type Config interface { } type config struct { - logger *zap.Logger + logger logging.Logger } func (c config) InitConfig(flags *pflag.FlagSet) { diff --git a/internal/config/multi_handler_config.go b/internal/config/multi_handler_config.go new file mode 100644 index 0000000..6ea35a6 --- /dev/null +++ b/internal/config/multi_handler_config.go @@ -0,0 +1,48 @@ +package config + +import ( + "github.com/spf13/viper" +) + +type MultiHandlerConfig interface { + HandlerName() string + ListenAddress() string + Ports() []uint16 + Options() *viper.Viper + HandlerConfigs() []HandlerConfig +} + +type multiHandlerConfig struct { + handlerName string + ports []uint16 + listenAddress string + options *viper.Viper +} + +func NewMultiHandlerConfig(handlerName string, ports []uint16, listenAddress string, options *viper.Viper) MultiHandlerConfig { + return &multiHandlerConfig{handlerName: handlerName, ports: ports, listenAddress: listenAddress, options: options} +} + +func (m multiHandlerConfig) HandlerName() string { + return m.handlerName +} + +func (m multiHandlerConfig) ListenAddress() string { + return m.listenAddress +} + +func (m multiHandlerConfig) Ports() []uint16 { + return m.ports +} + +func (m multiHandlerConfig) Options() *viper.Viper { + return m.options +} + +func (m multiHandlerConfig) HandlerConfigs() []HandlerConfig { + configs := make([]HandlerConfig, 0) + for _, port := range m.ports { + configs = append(configs, NewHandlerConfig(m.handlerName, port, m.listenAddress, m.options)) + } + return configs +} diff --git a/internal/config/multi_handler_config_test.go b/internal/config/multi_handler_config_test.go new file mode 100644 index 0000000..0d285e9 --- /dev/null +++ b/internal/config/multi_handler_config_test.go @@ -0,0 +1,240 @@ +package config + +import ( + "github.com/spf13/viper" + "reflect" + "testing" +) + +func Test_multiHandlerConfig_HandlerConfigs(t *testing.T) { + type fields struct { + handlerName string + ports []uint16 + listenAddress string + options *viper.Viper + } + tests := []struct { + name string + fields fields + want []HandlerConfig + }{ + { + name: "Get empty array if no ports are set", + fields: fields{}, + want: make([]HandlerConfig, 0), + }, + { + name: "Get a single handler config if only one port is set", + fields: fields{ + handlerName: "sampleHandler", + ports: []uint16{80}, + listenAddress: "0.0.0.0", + options: nil, + }, + want: []HandlerConfig{ + &handlerConfig{ + handlerName: "sampleHandler", + port: 80, + listenAddress: "0.0.0.0", + options: nil, + }, + }, + }, + { + name: "Get multiple handler configs if only one port is set", + fields: fields{ + handlerName: "sampleHandler", + ports: []uint16{80, 8080}, + listenAddress: "0.0.0.0", + options: nil, + }, + want: []HandlerConfig{ + &handlerConfig{ + handlerName: "sampleHandler", + port: 80, + listenAddress: "0.0.0.0", + options: nil, + }, + &handlerConfig{ + handlerName: "sampleHandler", + port: 8080, + listenAddress: "0.0.0.0", + options: nil, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := multiHandlerConfig{ + handlerName: tt.fields.handlerName, + ports: tt.fields.ports, + listenAddress: tt.fields.listenAddress, + options: tt.fields.options, + } + if got := m.HandlerConfigs(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("HandlerConfigs() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_multiHandlerConfig_HandlerName(t *testing.T) { + type fields struct { + handlerName string + ports []uint16 + listenAddress string + options *viper.Viper + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "Get empty handler name for uninitialized struct", + fields: fields{}, + want: "", + }, + { + name: "Get expected handler name for initialized struct", + fields: fields{ + handlerName: "sampleHandler", + }, + want: "sampleHandler", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := multiHandlerConfig{ + handlerName: tt.fields.handlerName, + ports: tt.fields.ports, + listenAddress: tt.fields.listenAddress, + options: tt.fields.options, + } + if got := m.HandlerName(); got != tt.want { + t.Errorf("HandlerName() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_multiHandlerConfig_ListenAddress(t *testing.T) { + type fields struct { + handlerName string + ports []uint16 + listenAddress string + options *viper.Viper + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "Get empty ListenAddress for uninitialized struct", + fields: fields{}, + want: "", + }, + { + name: "Get expected ListenAddress for initialized struct", + fields: fields{ + listenAddress: "0.0.0.0", + }, + want: "0.0.0.0", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := multiHandlerConfig{ + handlerName: tt.fields.handlerName, + ports: tt.fields.ports, + listenAddress: tt.fields.listenAddress, + options: tt.fields.options, + } + if got := m.ListenAddress(); got != tt.want { + t.Errorf("ListenAddress() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_multiHandlerConfig_Options(t *testing.T) { + type fields struct { + handlerName string + ports []uint16 + listenAddress string + options *viper.Viper + } + tests := []struct { + name string + fields fields + want *viper.Viper + }{ + { + name: "Get nil Options for uninitialized struct", + fields: fields{}, + want: nil, + }, + { + name: "Get expected Options for initialized struct", + fields: fields{ + options: viper.New(), + }, + want: viper.New(), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := multiHandlerConfig{ + handlerName: tt.fields.handlerName, + ports: tt.fields.ports, + listenAddress: tt.fields.listenAddress, + options: tt.fields.options, + } + if got := m.Options(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Options() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_multiHandlerConfig_Ports(t *testing.T) { + type fields struct { + handlerName string + ports []uint16 + listenAddress string + options *viper.Viper + } + tests := []struct { + name string + fields fields + want []uint16 + }{ + { + name: "Get empty Ports for uninitialized struct", + fields: fields{}, + want: nil, + }, + { + name: "Get expected Ports for initialized struct", + fields: fields{ + ports: []uint16{80, 8080}, + }, + want: []uint16{80, 8080}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := multiHandlerConfig{ + handlerName: tt.fields.handlerName, + ports: tt.fields.ports, + listenAddress: tt.fields.listenAddress, + options: tt.fields.options, + } + if got := m.Ports(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Ports() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/internal/config/parsing.go b/internal/config/parsing.go new file mode 100644 index 0000000..adc4a09 --- /dev/null +++ b/internal/config/parsing.go @@ -0,0 +1,26 @@ +package config + +import "github.com/spf13/viper" + +func CreateMultiHandlerConfig(handlerConfig *viper.Viper) MultiHandlerConfig { + return NewMultiHandlerConfig( + handlerConfig.GetString(pluginConfigKey), + portsFromConfig(handlerConfig), + handlerConfig.GetString(listenAddressConfigKey), + handlerConfig.Sub(OptionsKey), + ) +} + +func portsFromConfig(handlerConfig *viper.Viper) (ports []uint16) { + if portsInt := handlerConfig.GetIntSlice(portsConfigKey); len(portsInt) > 0 { + for _, port := range portsInt { + ports = append(ports, uint16(port)) + } + return + } + + if portInt := handlerConfig.GetInt(portConfigKey); portInt > 0 { + ports = append(ports, uint16(portInt)) + } + return +} diff --git a/internal/config/parsing_test.go b/internal/config/parsing_test.go new file mode 100644 index 0000000..5f1efb7 --- /dev/null +++ b/internal/config/parsing_test.go @@ -0,0 +1,145 @@ +package config + +import ( + "bytes" + "github.com/spf13/viper" + "reflect" + "testing" +) + +func TestCreateMultiHandlerConfig(t *testing.T) { + type args struct { + handlerConfig *viper.Viper + } + tests := []struct { + name string + args args + want MultiHandlerConfig + }{ + { + name: "Get simple multiHandlerConfig from config", + args: args{ + handlerConfig: configFromString(` +handler: sampleHandler +listenAddress: 0.0.0.0 +ports: +- 80 +- 8080 +options: {} +`), + }, + want: &multiHandlerConfig{ + handlerName: "sampleHandler", + ports: []uint16{80, 8080}, + listenAddress: "0.0.0.0", + options: viper.New(), + }, + }, + { + name: "Get more complex multiHandlerConfig from config", + args: args{ + handlerConfig: configFromString(` +handler: sampleHandler +listenAddress: 0.0.0.0 +ports: +- 80 +- 8080 +options: + optionA: asdf + optionB: as1234 +`), + }, + want: &multiHandlerConfig{ + handlerName: "sampleHandler", + ports: []uint16{80, 8080}, + listenAddress: "0.0.0.0", + options: configFromString(` +nesting: + optionA: asdf + optionB: as1234 +`).Sub("nesting"), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := CreateMultiHandlerConfig(tt.args.handlerConfig); !reflect.DeepEqual(got, tt.want) { + t.Errorf("CreateMultiHandlerConfig() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_portsFromConfig(t *testing.T) { + type args struct { + handlerConfig *viper.Viper + } + tests := []struct { + name string + args args + wantPorts []uint16 + }{ + { + name: "Empty array if config value is not set", + args: args{ + handlerConfig: viper.New(), + }, + wantPorts: nil, + }, + { + name: "Array of one if `port` is set", + args: args{ + handlerConfig: configFromString(` +port: 80 +`), + }, + wantPorts: []uint16{80}, + }, + { + name: "Array of one if `ports` is set as array", + args: args{ + handlerConfig: configFromString(` +ports: +- 80 +`), + }, + wantPorts: []uint16{80}, + }, + { + name: "Array of two if `ports` is set as array", + args: args{ + handlerConfig: configFromString(` +ports: +- 80 +- 8080 +`), + }, + wantPorts: []uint16{80, 8080}, + }, + { + name: "Array of two if `port` is set as array", + args: args{ + handlerConfig: configFromString(` +ports: +- 80 +- 8080 +`), + }, + wantPorts: []uint16{80, 8080}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if gotPorts := portsFromConfig(tt.args.handlerConfig); !reflect.DeepEqual(gotPorts, tt.wantPorts) { + t.Errorf("portsFromConfig() = %v, want %v", gotPorts, tt.wantPorts) + } + }) + } +} + +func configFromString(yaml string) (config *viper.Viper) { + config = viper.New() + config.SetConfigType("yaml") + _ = config.ReadConfig(bytes.NewBufferString(yaml)) + return +} diff --git a/internal/endpoints/endpoint.go b/internal/endpoints/endpoint.go new file mode 100644 index 0000000..b209339 --- /dev/null +++ b/internal/endpoints/endpoint.go @@ -0,0 +1,31 @@ +//go:generate mockgen -source=endpoint.go -destination=./../../mock/endpoint_mock.go -package=mock +package endpoints + +import ( + "github.com/baez90/inetmock/internal/config" + "github.com/baez90/inetmock/pkg/api" +) + +type Endpoint interface { + Start() error + Shutdown() error + Name() string +} + +type endpoint struct { + name string + handler api.ProtocolHandler + config config.HandlerConfig +} + +func (e endpoint) Name() string { + return e.name +} + +func (e *endpoint) Start() (err error) { + return e.handler.Start(e.config) +} + +func (e *endpoint) Shutdown() (err error) { + return e.handler.Shutdown() +} diff --git a/internal/endpoints/endpoint_manager.go b/internal/endpoints/endpoint_manager.go new file mode 100644 index 0000000..209e3b7 --- /dev/null +++ b/internal/endpoints/endpoint_manager.go @@ -0,0 +1,130 @@ +package endpoints + +import ( + "fmt" + "github.com/baez90/inetmock/internal/config" + "github.com/baez90/inetmock/internal/plugins" + "github.com/baez90/inetmock/pkg/logging" + "go.uber.org/zap" + "sync" + "time" +) + +type EndpointManager interface { + RegisteredEndpoints() []Endpoint + StartedEndpoints() []Endpoint + CreateEndpoint(name string, multiHandlerConfig config.MultiHandlerConfig) error + StartEndpoints() + ShutdownEndpoints() +} + +func NewEndpointManager(logger logging.Logger) EndpointManager { + return &endpointManager{ + logger: logger, + registry: plugins.Registry(), + } +} + +type endpointManager struct { + logger logging.Logger + registeredEndpoints []Endpoint + properlyStartedEndpoints []Endpoint + registry plugins.HandlerRegistry +} + +func (e endpointManager) RegisteredEndpoints() []Endpoint { + return e.registeredEndpoints +} + +func (e endpointManager) StartedEndpoints() []Endpoint { + return e.properlyStartedEndpoints +} + +func (e *endpointManager) CreateEndpoint(name string, multiHandlerConfig config.MultiHandlerConfig) (err error) { + if handler, ok := e.registry.HandlerForName(multiHandlerConfig.HandlerName()); ok { + for _, handlerConfig := range multiHandlerConfig.HandlerConfigs() { + e.registeredEndpoints = append(e.registeredEndpoints, &endpoint{ + name: name, + handler: handler, + config: handlerConfig, + }) + } + } else { + err = fmt.Errorf("no matching handler registered for name %s", multiHandlerConfig.HandlerName()) + } + return +} + +func (e *endpointManager) StartEndpoints() { + startTime := time.Now() + for _, endpoint := range e.registeredEndpoints { + endpointLogger := e.logger.With( + zap.String("endpoint", endpoint.Name()), + ) + endpointLogger.Info("Starting endpoint") + if ok := startEndpoint(endpoint, endpointLogger); ok { + e.properlyStartedEndpoints = append(e.properlyStartedEndpoints, endpoint) + endpointLogger.Info("successfully started endpoint") + } else { + endpointLogger.Error("error occurred during endpoint startup - will be skipped for now") + } + } + endpointStartupDuration := time.Since(startTime) + e.logger.Info( + "Startup of all endpoints completed", + zap.Duration("startupTime", endpointStartupDuration), + ) +} + +func (e *endpointManager) ShutdownEndpoints() { + var waitGroup sync.WaitGroup + waitGroup.Add(len(e.properlyStartedEndpoints)) + + for _, endpoint := range e.properlyStartedEndpoints { + endpointLogger := e.logger.With( + zap.String("endpoint", endpoint.Name()), + ) + endpointLogger.Info("Triggering shutdown of endpoint") + go shutdownEndpoint(endpoint, endpointLogger, &waitGroup) + } + + waitGroup.Wait() +} + +func startEndpoint(ep Endpoint, logger logging.Logger) (success bool) { + defer func() { + if r := recover(); r != nil { + logger.Fatal( + "recovered panic during startup of endpoint", + zap.Any("recovered", r), + ) + } + }() + if err := ep.Start(); err != nil { + logger.Error( + "failed to start endpoint", + zap.Error(err), + ) + } else { + success = true + } + return +} + +func shutdownEndpoint(ep Endpoint, logger logging.Logger, wg *sync.WaitGroup) { + defer func() { + if r := recover(); r != nil { + logger.Fatal( + "recovered panic during shutdown of endpoint", + zap.Any("recovered", r), + ) + } + wg.Done() + }() + if err := ep.Shutdown(); err != nil { + logger.Error( + "Failed to shutdown endpoint", + zap.Error(err), + ) + } +} diff --git a/internal/endpoints/endpoint_manager_test.go b/internal/endpoints/endpoint_manager_test.go new file mode 100644 index 0000000..b629cef --- /dev/null +++ b/internal/endpoints/endpoint_manager_test.go @@ -0,0 +1,116 @@ +package endpoints + +import ( + "github.com/baez90/inetmock/internal/config" + "github.com/baez90/inetmock/internal/plugins" + "github.com/baez90/inetmock/mock" + "github.com/baez90/inetmock/pkg/logging" + "github.com/golang/mock/gomock" + "testing" +) + +func Test_endpointManager_CreateEndpoint(t *testing.T) { + type fields struct { + logger logging.Logger + registeredEndpoints []Endpoint + properlyStartedEndpoints []Endpoint + registry plugins.HandlerRegistry + } + type args struct { + name string + multiHandlerConfig config.MultiHandlerConfig + } + tests := []struct { + name string + fields fields + args args + wantErr bool + wantEndpoints int + }{ + { + name: "Test add endpoint", + wantErr: false, + wantEndpoints: 1, + fields: fields{ + logger: func() logging.Logger { + return mock.NewMockLogger(gomock.NewController(t)) + }(), + registeredEndpoints: nil, + properlyStartedEndpoints: nil, + registry: func() plugins.HandlerRegistry { + registry := mock.NewMockHandlerRegistry(gomock.NewController(t)) + registry. + EXPECT(). + HandlerForName("sampleHandler"). + MinTimes(1). + MaxTimes(1). + Return(mock.NewMockProtocolHandler(gomock.NewController(t)), true) + return registry + }(), + }, + args: args{ + name: "sampleEndpoint", + multiHandlerConfig: config.NewMultiHandlerConfig( + "sampleHandler", + []uint16{80}, + "0.0.0.0", + nil, + ), + }, + }, + { + name: "Test add unknown handler", + wantErr: true, + wantEndpoints: 0, + fields: fields{ + logger: func() logging.Logger { + return mock.NewMockLogger(gomock.NewController(t)) + }(), + registeredEndpoints: nil, + properlyStartedEndpoints: nil, + registry: func() plugins.HandlerRegistry { + registry := mock.NewMockHandlerRegistry(gomock.NewController(t)) + registry. + EXPECT(). + HandlerForName("sampleHandler"). + MinTimes(1). + MaxTimes(1). + Return(nil, false) + return registry + }(), + }, + args: args{ + name: "sampleEndpoint", + multiHandlerConfig: config.NewMultiHandlerConfig( + "sampleHandler", + []uint16{80}, + "0.0.0.0", + nil, + ), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := &endpointManager{ + logger: tt.fields.logger, + registeredEndpoints: tt.fields.registeredEndpoints, + properlyStartedEndpoints: tt.fields.properlyStartedEndpoints, + registry: tt.fields.registry, + } + + if err := e.CreateEndpoint(tt.args.name, tt.args.multiHandlerConfig); (err != nil) != tt.wantErr { + t.Errorf("CreateEndpoint() error = %v, wantErr %v", err, tt.wantErr) + } + + if len(e.RegisteredEndpoints()) != tt.wantEndpoints { + t.Errorf("RegisteredEndpoints() = %d, want = 1", len(e.RegisteredEndpoints())) + return + } + + if len(e.RegisteredEndpoints()) > 0 && e.RegisteredEndpoints()[0].Name() != tt.args.name { + t.Errorf("Name() = %s, want = %s", e.RegisteredEndpoints()[0].Name(), tt.args.name) + } + }) + } +} diff --git a/internal/endpoints/endpoint_test.go b/internal/endpoints/endpoint_test.go new file mode 100644 index 0000000..d63a99f --- /dev/null +++ b/internal/endpoints/endpoint_test.go @@ -0,0 +1,179 @@ +package endpoints + +import ( + "fmt" + "github.com/baez90/inetmock/internal/config" + "github.com/baez90/inetmock/mock" + "github.com/baez90/inetmock/pkg/api" + "github.com/golang/mock/gomock" + "testing" +) + +func Test_endpoint_Name(t *testing.T) { + type fields struct { + name string + handler api.ProtocolHandler + config config.HandlerConfig + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "Empty Name if struct is uninitialized", + fields: fields{}, + want: "", + }, + { + name: "Expected Name if struct is initialized", + fields: fields{ + name: "sampleHandler", + }, + want: "sampleHandler", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := endpoint{ + name: tt.fields.name, + handler: tt.fields.handler, + config: tt.fields.config, + } + if got := e.Name(); got != tt.want { + t.Errorf("Name() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_endpoint_Shutdown(t *testing.T) { + type fields struct { + name string + handler api.ProtocolHandler + config config.HandlerConfig + } + tests := []struct { + name string + fields fields + wantErr bool + }{ + { + name: "Expect no error if mocked handler does not return one", + fields: fields{ + handler: func() api.ProtocolHandler { + handler := mock.NewMockProtocolHandler(gomock.NewController(t)) + handler.EXPECT(). + Shutdown(). + MaxTimes(1). + Return(nil) + return handler + }(), + }, + wantErr: false, + }, + { + name: "Expect error if mocked handler returns one", + fields: fields{ + handler: func() api.ProtocolHandler { + handler := mock.NewMockProtocolHandler(gomock.NewController(t)) + handler.EXPECT(). + Shutdown(). + MaxTimes(1). + Return(fmt.Errorf("")) + return handler + }(), + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := &endpoint{ + name: tt.fields.name, + handler: tt.fields.handler, + config: tt.fields.config, + } + if err := e.Shutdown(); (err != nil) != tt.wantErr { + t.Errorf("Shutdown() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func Test_endpoint_Start(t *testing.T) { + + demoHandlerConfig := config.NewHandlerConfig( + "sampleHandler", + 80, + "0.0.0.0", + nil, + ) + + type fields struct { + name string + handler api.ProtocolHandler + config config.HandlerConfig + } + tests := []struct { + name string + fields fields + wantErr bool + }{ + { + name: "Expect no error if mocked handler does not return one", + fields: fields{ + handler: func() api.ProtocolHandler { + handler := mock.NewMockProtocolHandler(gomock.NewController(t)) + handler.EXPECT(). + Start(nil). + MaxTimes(1). + Return(nil) + return handler + }(), + }, + wantErr: false, + }, + { + name: "Expect error if mocked handler returns one", + fields: fields{ + handler: func() api.ProtocolHandler { + handler := mock.NewMockProtocolHandler(gomock.NewController(t)) + handler.EXPECT(). + Start(nil). + MaxTimes(1). + Return(fmt.Errorf("")) + return handler + }(), + }, + wantErr: true, + }, + { + name: "Expect config to be passed to Start call", + fields: fields{ + config: demoHandlerConfig, + handler: func() api.ProtocolHandler { + handler := mock.NewMockProtocolHandler(gomock.NewController(t)) + handler.EXPECT(). + Start(demoHandlerConfig). + MaxTimes(1). + Return(fmt.Errorf("")) + return handler + }(), + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + e := &endpoint{ + name: tt.fields.name, + handler: tt.fields.handler, + config: tt.fields.config, + } + if err := e.Start(); (err != nil) != tt.wantErr { + t.Errorf("Start() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/internal/plugins/loading.go b/internal/plugins/loading.go index 1ef3ad7..5e67ab2 100644 --- a/internal/plugins/loading.go +++ b/internal/plugins/loading.go @@ -1,3 +1,4 @@ +//go:generate mockgen -source=loading.go -destination=./../../mock/plugins_mock.go -package=mock package plugins import ( @@ -42,7 +43,7 @@ func (h *handlerRegistry) HandlerForName(handlerName string) (instance api.Proto func (h *handlerRegistry) RegisterHandler(handlerName string, handlerProvider api.PluginInstanceFactory, subCommands ...*cobra.Command) { if _, exists := h.handlers[handlerName]; exists { - panic(fmt.Sprintf("plugin %s already registered - there's something strange...in the neighborhood")) + panic(fmt.Sprintf("handler with name %s is already registered - there's something strange...in the neighborhood", handlerName)) } h.handlers[handlerName] = handlerProvider diff --git a/internal/plugins/loading_test.go b/internal/plugins/loading_test.go new file mode 100644 index 0000000..7ad9ae7 --- /dev/null +++ b/internal/plugins/loading_test.go @@ -0,0 +1,109 @@ +package plugins + +import ( + "github.com/baez90/inetmock/pkg/api" + "github.com/spf13/cobra" + "reflect" + "testing" +) + +func Test_handlerRegistry_PluginCommands(t *testing.T) { + type fields struct { + handlers map[string]api.PluginInstanceFactory + pluginCommands []*cobra.Command + } + tests := []struct { + name string + fields fields + want []*cobra.Command + }{ + { + name: "Default is an nil array of commands", + fields: fields{}, + want: nil, + }, + { + name: "Returns a copy of the given array of commands", + fields: fields{ + pluginCommands: []*cobra.Command{ + { + Use: "my-super-command", + Short: "bla bla bla, description", + }, + }, + }, + want: []*cobra.Command{ + { + Use: "my-super-command", + Short: "bla bla bla, description", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h := handlerRegistry{ + handlers: tt.fields.handlers, + pluginCommands: tt.fields.pluginCommands, + } + if got := h.PluginCommands(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("PluginCommands() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_handlerRegistry_HandlerForName(t *testing.T) { + type fields struct { + handlers map[string]api.PluginInstanceFactory + pluginCommands []*cobra.Command + } + type args struct { + handlerName string + } + tests := []struct { + name string + fields fields + args args + wantInstance api.ProtocolHandler + wantOk bool + }{ + { + name: "No instance if nothing is registered", + fields: fields{}, + args: args{}, + wantInstance: nil, + wantOk: false, + }, + { + name: "Nil instance from pseudo factory", + fields: fields{ + handlers: map[string]api.PluginInstanceFactory{ + "pseudo": func() api.ProtocolHandler { + return nil + }, + }, + }, + args: args{ + handlerName: "pseudo", + }, + wantInstance: nil, + wantOk: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + h := &handlerRegistry{ + handlers: tt.fields.handlers, + pluginCommands: tt.fields.pluginCommands, + } + gotInstance, gotOk := h.HandlerForName(tt.args.handlerName) + if !reflect.DeepEqual(gotInstance, tt.wantInstance) { + t.Errorf("HandlerForName() gotInstance = %v, want %v", gotInstance, tt.wantInstance) + } + if gotOk != tt.wantOk { + t.Errorf("HandlerForName() gotOk = %v, want %v", gotOk, tt.wantOk) + } + }) + } +} diff --git a/mock_config.yaml b/mock_config.yaml index 450facc..ad98264 100644 --- a/mock_config.yaml +++ b/mock_config.yaml @@ -33,7 +33,9 @@ endpoints: plainHttp: handler: http_mock listenAddress: 0.0.0.0 - port: 80 + ports: + - 80 + - 8080 options: <<: *httpResponseRules proxy: @@ -46,7 +48,9 @@ endpoints: httpsDowngrade: handler: tls_interceptor listenAddress: 0.0.0.0 - port: 443 + ports: + - 443 + - 8443 options: <<: *tlsOptions target: diff --git a/pkg/api/protocol_handler.go b/pkg/api/protocol_handler.go index 5b3607a..27c99b3 100644 --- a/pkg/api/protocol_handler.go +++ b/pkg/api/protocol_handler.go @@ -1,9 +1,9 @@ +//go:generate mockgen -source=protocol_handler.go -destination=./../../mock/protocol_handler_mock.go -package=mock package api import ( "github.com/baez90/inetmock/internal/config" "go.uber.org/zap" - "sync" ) type PluginInstanceFactory func() ProtocolHandler @@ -11,6 +11,6 @@ type PluginInstanceFactory func() ProtocolHandler type LoggingFactory func() (*zap.Logger, error) type ProtocolHandler interface { - Start(config config.HandlerConfig) - Shutdown(wg *sync.WaitGroup) + Start(config config.HandlerConfig) error + Shutdown() error } diff --git a/pkg/logging/factory.go b/pkg/logging/factory.go index dc671ec..7ba4ea0 100644 --- a/pkg/logging/factory.go +++ b/pkg/logging/factory.go @@ -17,7 +17,9 @@ func ConfigureLogging( ) { loggingConfig.Level = level loggingConfig.Development = developmentLogging - loggingConfig.InitialFields = initialFields + if initialFields != nil { + loggingConfig.InitialFields = initialFields + } } func ParseLevel(levelString string) zap.AtomicLevel { @@ -37,6 +39,10 @@ func ParseLevel(levelString string) zap.AtomicLevel { } } -func CreateLogger() (*zap.Logger, error) { - return loggingConfig.Build() +func CreateLogger() (Logger, error) { + if zapLogger, err := loggingConfig.Build(); err != nil { + return nil, err + } else { + return NewLogger(zapLogger), nil + } } diff --git a/pkg/logging/factory_test.go b/pkg/logging/factory_test.go new file mode 100644 index 0000000..061462d --- /dev/null +++ b/pkg/logging/factory_test.go @@ -0,0 +1,166 @@ +package logging + +import ( + "go.uber.org/zap" + "reflect" + "testing" +) + +func TestParseLevel(t *testing.T) { + type args struct { + levelString string + } + tests := []struct { + name string + args args + want zap.AtomicLevel + }{ + { + name: "Test parse DEBUG level", + args: args{ + levelString: "DEBUG", + }, + want: zap.NewAtomicLevelAt(zap.DebugLevel), + }, + { + name: "Test parse DeBuG level", + args: args{ + levelString: "DeBuG", + }, + want: zap.NewAtomicLevelAt(zap.DebugLevel), + }, + { + name: "Test parse INFO level", + args: args{ + levelString: "INFO", + }, + want: zap.NewAtomicLevelAt(zap.InfoLevel), + }, + { + name: "Test parse InFo level", + args: args{ + levelString: "InFo", + }, + want: zap.NewAtomicLevelAt(zap.InfoLevel), + }, + { + name: "Test parse WARN level", + args: args{ + levelString: "WARN", + }, + want: zap.NewAtomicLevelAt(zap.WarnLevel), + }, + { + name: "Test parse WaRn level", + args: args{ + levelString: "WaRn", + }, + want: zap.NewAtomicLevelAt(zap.WarnLevel), + }, + { + name: "Test parse ERROR level", + args: args{ + levelString: "ERROR", + }, + want: zap.NewAtomicLevelAt(zap.ErrorLevel), + }, + { + name: "Test parse ErRoR level", + args: args{ + levelString: "ErRoR", + }, + want: zap.NewAtomicLevelAt(zap.ErrorLevel), + }, + { + name: "Test parse FATAL level", + args: args{ + levelString: "FATAL", + }, + want: zap.NewAtomicLevelAt(zap.FatalLevel), + }, + { + name: "Test parse FaTaL level", + args: args{ + levelString: "FaTaL", + }, + want: zap.NewAtomicLevelAt(zap.FatalLevel), + }, + { + name: "Fallback to INFO level if unknown level", + args: args{ + levelString: "asdf23423", + }, + want: zap.NewAtomicLevelAt(zap.InfoLevel), + }, + { + name: "Fallback to INFO level if no level", + args: args{ + levelString: "", + }, + want: zap.NewAtomicLevelAt(zap.InfoLevel), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := ParseLevel(tt.args.levelString); !reflect.DeepEqual(got, tt.want) { + t.Errorf("ParseLevel() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestConfigureLogging(t *testing.T) { + type args struct { + level zap.AtomicLevel + developmentLogging bool + initialFields map[string]interface{} + } + tests := []struct { + name string + args args + }{ + { + name: "Test configure defaults", + args: args{}, + }, + { + name: "Test configure with initialFields", + args: args{ + initialFields: map[string]interface{}{ + "asdf": "hello, World", + }, + }, + }, + { + name: "Test configure development logging enabled", + args: args{ + developmentLogging: true, + }, + }, + { + name: "Test configure log level", + args: args{ + level: zap.NewAtomicLevelAt(zap.FatalLevel), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ConfigureLogging(tt.args.level, tt.args.developmentLogging, tt.args.initialFields) + if loggingConfig.Development != tt.args.developmentLogging { + t.Errorf("loggingConfig.Development = %t, want %t", loggingConfig.Development, tt.args.developmentLogging) + return + } + + if loggingConfig.Level != tt.args.level { + t.Errorf("loggingConfig.Level = %v, want %v", loggingConfig.Level, tt.args.level) + return + } + + if tt.args.initialFields != nil && !reflect.DeepEqual(loggingConfig.InitialFields, tt.args.initialFields) { + t.Errorf("loggingConfig.InitialFields = %v, want %v", loggingConfig.InitialFields, tt.args.initialFields) + return + } + }) + } +} diff --git a/pkg/logging/logger.go b/pkg/logging/logger.go new file mode 100644 index 0000000..2cce141 --- /dev/null +++ b/pkg/logging/logger.go @@ -0,0 +1,60 @@ +//go:generate mockgen -source=logger.go -destination=./../../mock/logger_mock.go -package=mock +package logging + +import "go.uber.org/zap" + +type Logger interface { + Named(s string) Logger + With(fields ...zap.Field) Logger + Debug(msg string, fields ...zap.Field) + Info(msg string, fields ...zap.Field) + Warn(msg string, fields ...zap.Field) + Error(msg string, fields ...zap.Field) + Panic(msg string, fields ...zap.Field) + Fatal(msg string, fields ...zap.Field) + Sync() error +} + +type logger struct { + underlyingLogger *zap.Logger +} + +func NewLogger(underlyingLogger *zap.Logger) *logger { + return &logger{underlyingLogger: underlyingLogger} +} + +func (l logger) Named(s string) Logger { + return NewLogger(l.underlyingLogger.Named(s)) +} + +func (l logger) With(fields ...zap.Field) Logger { + return NewLogger(l.underlyingLogger.With(fields...)) +} + +func (l logger) Debug(msg string, fields ...zap.Field) { + l.underlyingLogger.Debug(msg, fields...) +} + +func (l logger) Info(msg string, fields ...zap.Field) { + l.underlyingLogger.Info(msg, fields...) +} + +func (l logger) Warn(msg string, fields ...zap.Field) { + l.underlyingLogger.Warn(msg, fields...) +} + +func (l logger) Error(msg string, fields ...zap.Field) { + l.underlyingLogger.Error(msg, fields...) +} + +func (l logger) Panic(msg string, fields ...zap.Field) { + l.underlyingLogger.Panic(msg, fields...) +} + +func (l logger) Fatal(msg string, fields ...zap.Field) { + l.underlyingLogger.Fatal(msg, fields...) +} + +func (l logger) Sync() error { + return l.underlyingLogger.Sync() +} diff --git a/plugins/dns_mock/go.sum b/plugins/dns_mock/go.sum index 3a5b570..689d313 100644 --- a/plugins/dns_mock/go.sum +++ b/plugins/dns_mock/go.sum @@ -34,6 +34,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -187,6 +188,7 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -196,6 +198,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -225,3 +228,5 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/plugins/dns_mock/main.go b/plugins/dns_mock/main.go index 27f30b6..6b1ff1c 100644 --- a/plugins/dns_mock/main.go +++ b/plugins/dns_mock/main.go @@ -3,17 +3,17 @@ package main import ( "fmt" "github.com/baez90/inetmock/internal/config" + "github.com/baez90/inetmock/pkg/logging" "github.com/miekg/dns" "go.uber.org/zap" - "sync" ) type dnsHandler struct { - logger *zap.Logger + logger logging.Logger dnsServer []*dns.Server } -func (d *dnsHandler) Start(config config.HandlerConfig) { +func (d *dnsHandler) Start(config config.HandlerConfig) (err error) { options := loadFromConfig(config.Options()) addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) @@ -51,6 +51,7 @@ func (d *dnsHandler) Start(config config.HandlerConfig) { for _, dnsServer := range d.dnsServer { go d.startServer(dnsServer) } + return } func (d *dnsHandler) startServer(dnsServer *dns.Server) { @@ -62,7 +63,7 @@ func (d *dnsHandler) startServer(dnsServer *dns.Server) { } } -func (d *dnsHandler) Shutdown(wg *sync.WaitGroup) { +func (d *dnsHandler) Shutdown() error { d.logger.Info("shutting down DNS mock") for _, dnsServer := range d.dnsServer { if err := dnsServer.Shutdown(); err != nil { @@ -72,5 +73,5 @@ func (d *dnsHandler) Shutdown(wg *sync.WaitGroup) { ) } } - wg.Done() + return nil } diff --git a/plugins/dns_mock/regex_handler.go b/plugins/dns_mock/regex_handler.go index fb3cc0e..d245bcb 100644 --- a/plugins/dns_mock/regex_handler.go +++ b/plugins/dns_mock/regex_handler.go @@ -1,6 +1,7 @@ package main import ( + "github.com/baez90/inetmock/pkg/logging" "github.com/miekg/dns" "go.uber.org/zap" ) @@ -8,7 +9,7 @@ import ( type regexHandler struct { routes []resolverRule fallback ResolverFallback - logger *zap.Logger + logger logging.Logger } func (r2 *regexHandler) AddRule(rule resolverRule) { diff --git a/plugins/http_mock/go.sum b/plugins/http_mock/go.sum index 34c4685..0495479 100644 --- a/plugins/http_mock/go.sum +++ b/plugins/http_mock/go.sum @@ -34,6 +34,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -177,6 +178,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -186,6 +188,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -215,3 +218,5 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/plugins/http_mock/http_handler.go b/plugins/http_mock/http_handler.go index 987c4d7..57a4d67 100644 --- a/plugins/http_mock/http_handler.go +++ b/plugins/http_mock/http_handler.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "github.com/baez90/inetmock/pkg/logging" "go.uber.org/zap" "net/http" ) @@ -16,7 +17,7 @@ func (p *httpHandler) setupRoute(rule targetRule) { p.router.Handler(rule.Pattern(), createHandlerForTarget(p.logger, rule.response)) } -func createHandlerForTarget(logger *zap.Logger, targetPath string) http.Handler { +func createHandlerForTarget(logger logging.Logger, targetPath string) http.Handler { return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { headerWriter := &bytes.Buffer{} request.Header.Write(headerWriter) diff --git a/plugins/http_mock/main.go b/plugins/http_mock/main.go index 6f586a2..27a1362 100644 --- a/plugins/http_mock/main.go +++ b/plugins/http_mock/main.go @@ -3,9 +3,9 @@ package main import ( "fmt" "github.com/baez90/inetmock/internal/config" + "github.com/baez90/inetmock/pkg/logging" "go.uber.org/zap" "net/http" - "sync" ) const ( @@ -13,12 +13,12 @@ const ( ) type httpHandler struct { - logger *zap.Logger + logger logging.Logger router *RegexpHandler server *http.Server } -func (p *httpHandler) Start(config config.HandlerConfig) { +func (p *httpHandler) Start(config config.HandlerConfig) (err error) { options := loadFromConfig(config.Options()) addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) p.server = &http.Server{Addr: addr, Handler: p.router} @@ -31,18 +31,22 @@ func (p *httpHandler) Start(config config.HandlerConfig) { } go p.startServer() + return } -func (p *httpHandler) Shutdown(wg *sync.WaitGroup) { +func (p *httpHandler) Shutdown() (err error) { p.logger.Info("Shutting down HTTP mock") - if err := p.server.Close(); err != nil { + if err = p.server.Close(); err != nil { p.logger.Error( "failed to shutdown HTTP server", zap.Error(err), ) + err = fmt.Errorf( + "failed to shutdown HTTP server: %w", + err, + ) } - - wg.Done() + return } func (p *httpHandler) startServer() { diff --git a/plugins/http_proxy/go.sum b/plugins/http_proxy/go.sum index 6397fa2..0703ef9 100644 --- a/plugins/http_proxy/go.sum +++ b/plugins/http_proxy/go.sum @@ -38,6 +38,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -182,6 +183,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -191,6 +193,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -222,3 +225,5 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/plugins/http_proxy/main.go b/plugins/http_proxy/main.go index 08b5496..0176053 100644 --- a/plugins/http_proxy/main.go +++ b/plugins/http_proxy/main.go @@ -3,10 +3,10 @@ package main import ( "fmt" "github.com/baez90/inetmock/internal/config" + "github.com/baez90/inetmock/pkg/logging" "go.uber.org/zap" "gopkg.in/elazarl/goproxy.v1" "net/http" - "sync" ) const ( @@ -14,12 +14,12 @@ const ( ) type httpProxy struct { - logger *zap.Logger + logger logging.Logger proxy *goproxy.ProxyHttpServer server *http.Server } -func (h *httpProxy) Start(config config.HandlerConfig) { +func (h *httpProxy) Start(config config.HandlerConfig) (err error) { options := loadFromConfig(config.Options()) addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) h.server = &http.Server{Addr: addr, Handler: h.proxy} @@ -33,6 +33,7 @@ func (h *httpProxy) Start(config config.HandlerConfig) { } h.proxy.OnRequest().Do(proxyHandler) go h.startProxy() + return } func (h *httpProxy) startProxy() { @@ -44,13 +45,18 @@ func (h *httpProxy) startProxy() { } } -func (h *httpProxy) Shutdown(wg *sync.WaitGroup) { - defer wg.Done() +func (h *httpProxy) Shutdown() (err error) { h.logger.Info("Shutting down HTTP proxy") - if err := h.server.Close(); err != nil { + if err = h.server.Close(); err != nil { h.logger.Error( "failed to shutdown proxy endpoint", zap.Error(err), ) + + err = fmt.Errorf( + "failed to shutdown proxy endpoint: %w", + err, + ) } + return } diff --git a/plugins/http_proxy/proxy_handler.go b/plugins/http_proxy/proxy_handler.go index b0a3798..55a6e8c 100644 --- a/plugins/http_proxy/proxy_handler.go +++ b/plugins/http_proxy/proxy_handler.go @@ -1,6 +1,7 @@ package main import ( + "github.com/baez90/inetmock/pkg/logging" "go.uber.org/zap" "gopkg.in/elazarl/goproxy.v1" "io" @@ -12,7 +13,7 @@ import ( type proxyHttpHandler struct { options httpProxyOptions - logger *zap.Logger + logger logging.Logger } /* diff --git a/plugins/tls_interceptor/cert_store.go b/plugins/tls_interceptor/cert_store.go index 807674e..229348d 100644 --- a/plugins/tls_interceptor/cert_store.go +++ b/plugins/tls_interceptor/cert_store.go @@ -6,6 +6,7 @@ import ( "crypto/x509" "crypto/x509/pkix" "fmt" + "github.com/baez90/inetmock/pkg/logging" "github.com/baez90/inetmock/pkg/path" "go.uber.org/zap" "math/big" @@ -22,7 +23,7 @@ type certStore struct { caPrivateKey interface{} certCache map[string]*tls.Certificate timeSourceInstance timeSource - logger *zap.Logger + logger logging.Logger } func (cs *certStore) timeSource() timeSource { diff --git a/plugins/tls_interceptor/cert_store_test.go b/plugins/tls_interceptor/cert_store_test.go index a4de478..31ebe6e 100644 --- a/plugins/tls_interceptor/cert_store_test.go +++ b/plugins/tls_interceptor/cert_store_test.go @@ -3,6 +3,7 @@ package main import ( "crypto/tls" "crypto/x509" + "github.com/baez90/inetmock/pkg/logging" "go.uber.org/zap" "io/ioutil" "os" @@ -85,7 +86,8 @@ func Test_generateDomainCert(t *testing.T) { }, } - logger, _ := zap.NewDevelopment() + zapLogger, _ := zap.NewDevelopment() + logger := logging.NewLogger(zapLogger) certStore := certStore{ options: options, diff --git a/plugins/tls_interceptor/generate_ca_cmd.go b/plugins/tls_interceptor/generate_ca_cmd.go index 7ac59ae..fe60313 100644 --- a/plugins/tls_interceptor/generate_ca_cmd.go +++ b/plugins/tls_interceptor/generate_ca_cmd.go @@ -1,6 +1,7 @@ package main import ( + "github.com/baez90/inetmock/pkg/logging" "github.com/spf13/cobra" "go.uber.org/zap" "time" @@ -14,7 +15,7 @@ const ( generateCANotAfterRelative = "not-after" ) -func generateCACmd(logger *zap.Logger) *cobra.Command { +func generateCACmd(logger logging.Logger) *cobra.Command { cmd := &cobra.Command{ Use: "generate-ca", Short: "Generate a new CA certificate and corresponding key", @@ -31,7 +32,7 @@ func generateCACmd(logger *zap.Logger) *cobra.Command { return cmd } -func getDurationFlag(cmd *cobra.Command, flagName string, logger *zap.Logger) (val time.Duration, err error) { +func getDurationFlag(cmd *cobra.Command, flagName string, logger logging.Logger) (val time.Duration, err error) { if val, err = cmd.Flags().GetDuration(flagName); err != nil { logger.Error( "failed to parse parse flag", @@ -42,7 +43,7 @@ func getDurationFlag(cmd *cobra.Command, flagName string, logger *zap.Logger) (v return } -func getStringFlag(cmd *cobra.Command, flagName string, logger *zap.Logger) (val string, err error) { +func getStringFlag(cmd *cobra.Command, flagName string, logger logging.Logger) (val string, err error) { if val, err = cmd.Flags().GetString(flagName); err != nil { logger.Error( "failed to parse parse flag", @@ -53,7 +54,7 @@ func getStringFlag(cmd *cobra.Command, flagName string, logger *zap.Logger) (val return } -func runGenerateCA(logger *zap.Logger) func(cmd *cobra.Command, args []string) { +func runGenerateCA(logger logging.Logger) func(cmd *cobra.Command, args []string) { return func(cmd *cobra.Command, args []string) { var certOutPath, keyOutPath, curveName string var notBefore, notAfter time.Duration diff --git a/plugins/tls_interceptor/go.sum b/plugins/tls_interceptor/go.sum index 34c4685..0495479 100644 --- a/plugins/tls_interceptor/go.sum +++ b/plugins/tls_interceptor/go.sum @@ -34,6 +34,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -177,6 +178,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -186,6 +188,7 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -215,3 +218,5 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/plugins/tls_interceptor/main.go b/plugins/tls_interceptor/main.go index 24af7d3..550d4f0 100644 --- a/plugins/tls_interceptor/main.go +++ b/plugins/tls_interceptor/main.go @@ -5,6 +5,7 @@ import ( "crypto/x509" "fmt" "github.com/baez90/inetmock/internal/config" + "github.com/baez90/inetmock/pkg/logging" "go.uber.org/zap" "net" "sync" @@ -16,7 +17,7 @@ const ( ) type tlsInterceptor struct { - logger *zap.Logger + logger logging.Logger listener net.Listener certStore *certStore options *tlsOptions @@ -25,8 +26,7 @@ type tlsInterceptor struct { currentConnections []*proxyConn } -func (t *tlsInterceptor) Start(config config.HandlerConfig) { - var err error +func (t *tlsInterceptor) Start(config config.HandlerConfig) (err error) { t.options = loadFromConfig(config.Options()) addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) @@ -46,6 +46,11 @@ func (t *tlsInterceptor) Start(config config.HandlerConfig) { "failed to initialize CA cert", zap.Error(err), ) + err = fmt.Errorf( + "failed to initialize CA cert: %w", + err, + ) + return } rootCaPool := x509.NewCertPool() @@ -61,13 +66,18 @@ func (t *tlsInterceptor) Start(config config.HandlerConfig) { "failed to create tls listener", zap.Error(err), ) + err = fmt.Errorf( + "failed to create tls listener: %w", + err, + ) return } go t.startListener() + return } -func (t *tlsInterceptor) Shutdown(wg *sync.WaitGroup) { +func (t *tlsInterceptor) Shutdown() (err error) { t.logger.Info("Shutting down TLS interceptor") t.shutdownRequested = true done := make(chan struct{}) @@ -78,17 +88,21 @@ func (t *tlsInterceptor) Shutdown(wg *sync.WaitGroup) { select { case <-done: - wg.Done() + return case <-time.After(5 * time.Second): for _, proxyConn := range t.currentConnections { - if err := proxyConn.Close(); err != nil { + if err = proxyConn.Close(); err != nil { t.logger.Error( "error while closing remaining proxy connections", zap.Error(err), ) + err = fmt.Errorf( + "error while closing remaining proxy connections: %w", + err, + ) } } - wg.Done() + return } } From 43d3c62e015e220e5e9b8f1cdd6a6400c6b3c491 Mon Sep 17 00:00:00 2001 From: Peter Kurfer Date: Tue, 14 Apr 2020 00:20:22 +0200 Subject: [PATCH 7/9] Move mocks to internal package --- internal/endpoints/endpoint.go | 2 +- internal/endpoints/endpoint_manager_test.go | 2 +- internal/endpoints/endpoint_test.go | 2 +- internal/plugins/loading.go | 2 +- pkg/api/protocol_handler.go | 2 +- pkg/logging/logger.go | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/endpoints/endpoint.go b/internal/endpoints/endpoint.go index b209339..0394e86 100644 --- a/internal/endpoints/endpoint.go +++ b/internal/endpoints/endpoint.go @@ -1,4 +1,4 @@ -//go:generate mockgen -source=endpoint.go -destination=./../../mock/endpoint_mock.go -package=mock +//go:generate mockgen -source=endpoint.go -destination=./../../internal/mock/endpoint_mock.go -package=mock package endpoints import ( diff --git a/internal/endpoints/endpoint_manager_test.go b/internal/endpoints/endpoint_manager_test.go index b629cef..30a6668 100644 --- a/internal/endpoints/endpoint_manager_test.go +++ b/internal/endpoints/endpoint_manager_test.go @@ -2,8 +2,8 @@ package endpoints import ( "github.com/baez90/inetmock/internal/config" + "github.com/baez90/inetmock/internal/mock" "github.com/baez90/inetmock/internal/plugins" - "github.com/baez90/inetmock/mock" "github.com/baez90/inetmock/pkg/logging" "github.com/golang/mock/gomock" "testing" diff --git a/internal/endpoints/endpoint_test.go b/internal/endpoints/endpoint_test.go index d63a99f..3b6e687 100644 --- a/internal/endpoints/endpoint_test.go +++ b/internal/endpoints/endpoint_test.go @@ -3,7 +3,7 @@ package endpoints import ( "fmt" "github.com/baez90/inetmock/internal/config" - "github.com/baez90/inetmock/mock" + "github.com/baez90/inetmock/internal/mock" "github.com/baez90/inetmock/pkg/api" "github.com/golang/mock/gomock" "testing" diff --git a/internal/plugins/loading.go b/internal/plugins/loading.go index 5e67ab2..4fcd376 100644 --- a/internal/plugins/loading.go +++ b/internal/plugins/loading.go @@ -1,4 +1,4 @@ -//go:generate mockgen -source=loading.go -destination=./../../mock/plugins_mock.go -package=mock +//go:generate mockgen -source=loading.go -destination=./../../internal/mock/handler_registry_mock.go -package=mock package plugins import ( diff --git a/pkg/api/protocol_handler.go b/pkg/api/protocol_handler.go index 27c99b3..182133d 100644 --- a/pkg/api/protocol_handler.go +++ b/pkg/api/protocol_handler.go @@ -1,4 +1,4 @@ -//go:generate mockgen -source=protocol_handler.go -destination=./../../mock/protocol_handler_mock.go -package=mock +//go:generate mockgen -source=protocol_handler.go -destination=./../../internal/mock/protocol_handler_mock.go -package=mock package api import ( diff --git a/pkg/logging/logger.go b/pkg/logging/logger.go index 2cce141..22f4be9 100644 --- a/pkg/logging/logger.go +++ b/pkg/logging/logger.go @@ -1,4 +1,4 @@ -//go:generate mockgen -source=logger.go -destination=./../../mock/logger_mock.go -package=mock +//go:generate mockgen -source=logger.go -destination=./../../internal/mock/logger_mock.go -package=mock package logging import "go.uber.org/zap" From 7c2a41ad257cc729ade2f85bf5299ca2da56783b Mon Sep 17 00:00:00 2001 From: Peter Kurfer Date: Sun, 26 Apr 2020 00:22:45 +0200 Subject: [PATCH 8/9] Move TLS/cert handling to main app - apply changes in proxy plugin and TLS interceptor - add HTTPS proxy support - move ca-generation command to main app - minor refactoring to improve API stability - move mocks to extra packages to avoid cycling imports - fix bug in multi-port configuration - change HTTP proxy to redirect to HTTP mock instead of maintaining custom rules --- .dockerignore | 10 +- .goreleaser.yml | 2 +- Dockerfile | 4 +- Makefile | 23 +- go.mod | 4 +- go.sum | 8 +- internal/cmd/ca.go | 144 +++++++++ internal/cmd/init.go | 14 +- internal/cmd/plugins.go | 2 +- internal/config/multi_handler_config.go | 9 +- internal/config/multi_handler_config_test.go | 30 +- internal/config/parsing.go | 11 +- internal/endpoints/endpoint.go | 5 +- internal/endpoints/endpoint_manager.go | 13 +- internal/endpoints/endpoint_manager_test.go | 14 +- internal/endpoints/endpoint_test.go | 21 +- internal/plugins/loading.go | 2 +- mock_config.yaml | 15 +- .../config => pkg/api}/handler_config.go | 9 +- .../config => pkg/api}/handler_config_test.go | 2 +- pkg/api/protocol_handler.go | 5 +- pkg/api/services.go | 41 +++ pkg/cert/addr_utils.go | 22 ++ .../cert}/addr_utils_test.go | 2 +- pkg/cert/cache.go | 78 +++++ pkg/cert/cache_test.go | 299 ++++++++++++++++++ pkg/cert/constants.go | 21 ++ pkg/cert/defaults.go | 43 +++ pkg/cert/defaults_test.go | 39 +++ pkg/cert/generator.go | 184 +++++++++++ pkg/cert/options.go | 79 +++++ pkg/cert/options_test.go | 137 ++++++++ pkg/cert/pem.go | 79 +++++ pkg/cert/store.go | 153 +++++++++ pkg/cert/time_source.go | 20 ++ pkg/defaulting/defaulter.go | 43 +++ pkg/defaulting/defaulter_test.go | 111 +++++++ pkg/logging/logger.go | 2 +- plugins/dns_mock/go.mod | 2 +- plugins/dns_mock/go.sum | 4 + plugins/dns_mock/main.go | 4 +- plugins/http_mock/go.mod | 2 +- plugins/http_mock/go.sum | 4 + plugins/http_mock/main.go | 4 +- plugins/http_proxy/fallback.go | 53 ---- plugins/http_proxy/fallback_test.go | 46 --- plugins/http_proxy/go.mod | 3 +- plugins/http_proxy/go.sum | 4 + plugins/http_proxy/main.go | 13 +- plugins/http_proxy/protocol_options.go | 50 ++- plugins/http_proxy/protocol_options_test.go | 125 -------- plugins/http_proxy/proxy_handler.go | 123 ++++--- plugins/tls_interceptor/addr_utils.go | 20 -- plugins/tls_interceptor/cert_store.go | 204 ------------ plugins/tls_interceptor/cert_store_test.go | 213 ------------- plugins/tls_interceptor/certs.go | 106 ------- plugins/tls_interceptor/certs_test.go | 74 ----- plugins/tls_interceptor/generate_ca_cmd.go | 113 ------- plugins/tls_interceptor/go.mod | 3 +- plugins/tls_interceptor/go.sum | 4 + plugins/tls_interceptor/init.go | 2 +- plugins/tls_interceptor/main.go | 55 +--- plugins/tls_interceptor/protocol_options.go | 53 +--- plugins/tls_interceptor/test_setup.go | 55 ---- plugins/tls_interceptor/time_source.go | 18 -- 65 files changed, 1722 insertions(+), 1335 deletions(-) create mode 100644 internal/cmd/ca.go rename {internal/config => pkg/api}/handler_config.go (82%) rename {internal/config => pkg/api}/handler_config_test.go (99%) create mode 100644 pkg/api/services.go create mode 100644 pkg/cert/addr_utils.go rename {plugins/tls_interceptor => pkg/cert}/addr_utils_test.go (98%) create mode 100644 pkg/cert/cache.go create mode 100644 pkg/cert/cache_test.go create mode 100644 pkg/cert/constants.go create mode 100644 pkg/cert/defaults.go create mode 100644 pkg/cert/defaults_test.go create mode 100644 pkg/cert/generator.go create mode 100644 pkg/cert/options.go create mode 100644 pkg/cert/options_test.go create mode 100644 pkg/cert/pem.go create mode 100644 pkg/cert/store.go create mode 100644 pkg/cert/time_source.go create mode 100644 pkg/defaulting/defaulter.go create mode 100644 pkg/defaulting/defaulter_test.go delete mode 100644 plugins/http_proxy/fallback.go delete mode 100644 plugins/http_proxy/fallback_test.go delete mode 100644 plugins/tls_interceptor/addr_utils.go delete mode 100644 plugins/tls_interceptor/cert_store.go delete mode 100644 plugins/tls_interceptor/cert_store_test.go delete mode 100644 plugins/tls_interceptor/certs.go delete mode 100644 plugins/tls_interceptor/certs_test.go delete mode 100644 plugins/tls_interceptor/generate_ca_cmd.go delete mode 100644 plugins/tls_interceptor/test_setup.go delete mode 100644 plugins/tls_interceptor/time_source.go diff --git a/.dockerignore b/.dockerignore index 4a827a5..1446b07 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,16 +3,22 @@ ############### .git/ -plugins/ +.idea/ +.vscode/ +deploy/ +dist/ +doc/ ######### # Files # ######### +*.so *.out main inetmock README.md +LICENSE .dockerignore .gitignore -Dockerfile \ No newline at end of file +Dockerfile diff --git a/.goreleaser.yml b/.goreleaser.yml index 2f81f84..dad29e5 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -3,7 +3,7 @@ before: hooks: # You may remove this if you don't use go modules. - - make handlers + - make plugins builds: - id: "default" ldflags: diff --git a/Dockerfile b/Dockerfile index 11f3c66..a768875 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,8 +38,8 @@ WORKDIR /app COPY --from=build /etc/passwd /etc/group /etc/ COPY --from=build --chown=$USER /work/inetmock ./ -COPY --from=build --chown=$USER /work/plugins/ ./plugins/ +COPY --from=build --chown=$USER /work/*.so ./plugins/ USER $USER:$USER -ENTRYPOINT ["/app/inetmock"] \ No newline at end of file +ENTRYPOINT ["/app/inetmock"] diff --git a/Makefile b/Makefile index 46debe7..5e073af 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,8 @@ -VERSst/pluginsION = $(shell git describe --dirty --tags --always) +VERSION = $(shell git describe --dirty --tags --always) DIR = $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) BUILD_PATH = $(DIR)/main.go PKGS = $(shell go list ./...) -TEST_PKGS = $(shell find . -type f -name "*_test.go" -not -path "./plugins/*" -printf '%h\n' | sort -u) -GO_GEN_FILES = $(shell grep -rnwl --include="*.go" "go:generate" $(DIR)) +TEST_PKGS = $(shell find . -type f -name "*_test.go" -not -path "./plugins/*" -not -path "*/mock/*" -printf '%h\n' | sort -u) GOARGS = GOOS=linux GOARCH=amd64 GO_BUILD_ARGS = -ldflags="-w -s" GO_CONTAINER_BUILD_ARGS = -ldflags="-w -s" -a -installsuffix cgo @@ -12,8 +11,10 @@ BINARY_NAME = inetmock PLUGINS = $(wildcard $(DIR)plugins/*/.) DEBUG_PORT = 2345 DEBUG_ARGS?= --development-logs=true +CONTAINER_BUILDER ?= podman +DOCKER_IMAGE ?= inetmock -.PHONY: clean all format deps update-deps compile debug generate snapshot-release test cli-cover-report html-cover-report plugins $(PLUGINS) $(.PHONY: clean all format deps update-deps compile debug generate snapshot-release test cli-cover-report html-cover-report plugins $(PLUGINS) $(GO_GEN_FILES) +.PHONY: clean all format deps update-deps compile debug generate snapshot-release test cli-cover-report html-cover-report plugins $(PLUGINS) $(GO_GEN_FILES) all: clean format compile test plugins clean: @@ -45,26 +46,26 @@ endif debug: export INETMOCK_PLUGINS_DIRECTORY = $(DIR) debug: - dlv exec $(DIR)$(BINARY_NAME) \ + dlv debug $(DIR) \ --headless \ --listen=:2345 \ --api-version=2 \ - --accept-multiclient \ -- $(DEBUG_ARGS) generate: - @for go_gen_target in $(GO_GEN_FILES); do \ - go generate $$go_gen_target; \ - done + @go generate ./... snapshot-release: @goreleaser release --snapshot --skip-publish --rm-dist +container: + @$(CONTAINER_BUILDER) build -t $(DOCKER_IMAGE):latest -f $(DIR)Dockerfile $(DIR) + test: @go test -coverprofile=./cov-raw.out -v $(TEST_PKGS) @cat ./cov-raw.out | grep -v "generated" > ./cov.out -cli-cover-report: +cli-cover-report: test @go tool cover -func=cov.out html-cover-report: test @@ -72,4 +73,4 @@ html-cover-report: test plugins: $(PLUGINS) $(PLUGINS): - $(MAKE) -C $@ \ No newline at end of file + $(MAKE) -C $@ diff --git a/go.mod b/go.mod index c8d8d9d..2c56929 100644 --- a/go.mod +++ b/go.mod @@ -13,8 +13,8 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.6.3 - go.uber.org/zap v1.14.1 - golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa // indirect + go.uber.org/zap v1.15.0 + golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f // indirect golang.org/x/text v0.3.2 // indirect golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 // indirect gopkg.in/ini.v1 v1.55.0 // indirect diff --git a/go.sum b/go.sum index 36f19f8..cd32ca1 100644 --- a/go.sum +++ b/go.sum @@ -147,8 +147,8 @@ go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKY go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= -go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -178,8 +178,8 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h 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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= -golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= diff --git a/internal/cmd/ca.go b/internal/cmd/ca.go new file mode 100644 index 0000000..9c0c439 --- /dev/null +++ b/internal/cmd/ca.go @@ -0,0 +1,144 @@ +package cmd + +import ( + "crypto/tls" + "crypto/x509" + "github.com/baez90/inetmock/pkg/cert" + "github.com/baez90/inetmock/pkg/logging" + "github.com/spf13/cobra" + "go.uber.org/zap" + "time" +) + +const ( + generateCACommonName = "cn" + generateCaOrganizationName = "o" + generateCaOrganizationalUnitName = "ou" + generateCaCountryName = "c" + generateCaLocalityName = "l" + generateCaStateName = "st" + generateCaStreetAddressName = "street-address" + generateCaPostalCodeName = "postal-code" + generateCACertOutPath = "out-dir" + generateCACurveName = "curve" + generateCANotBeforeRelative = "not-before" + generateCANotAfterRelative = "not-after" +) + +var ( + generateCaCmd *cobra.Command + caCertOptions cert.GenerationOptions +) + +func init() { + generateCaCmd = &cobra.Command{ + Use: "generate-ca", + Short: "Generate a new CA certificate and corresponding key", + Long: ``, + Run: runGenerateCA, + } + + generateCaCmd.Flags().StringVar(&caCertOptions.CommonName, generateCACommonName, "INetMock", "Certificate Common Name that will also be used as file name during generation.") + generateCaCmd.Flags().StringSliceVar(&caCertOptions.Organization, generateCaOrganizationName, nil, "Organization information to append to certificate") + generateCaCmd.Flags().StringSliceVar(&caCertOptions.OrganizationalUnit, generateCaOrganizationalUnitName, nil, "Organizational unit information to append to certificate") + generateCaCmd.Flags().StringSliceVar(&caCertOptions.Country, generateCaCountryName, nil, "Country information to append to certificate") + generateCaCmd.Flags().StringSliceVar(&caCertOptions.Province, generateCaStateName, nil, "State information to append to certificate") + generateCaCmd.Flags().StringSliceVar(&caCertOptions.Locality, generateCaLocalityName, nil, "Locality information to append to certificate") + generateCaCmd.Flags().StringSliceVar(&caCertOptions.StreetAddress, generateCaStreetAddressName, nil, "Street address information to append to certificate") + generateCaCmd.Flags().StringSliceVar(&caCertOptions.PostalCode, generateCaPostalCodeName, nil, "Postal code information to append to certificate") + generateCaCmd.Flags().String(generateCACertOutPath, "", "Path where CA files should be stored") + generateCaCmd.Flags().String(generateCACurveName, "", "Name of the curve to use, if empty ED25519 is used, other valid values are [P224, P256,P384,P521]") + generateCaCmd.Flags().Duration(generateCANotBeforeRelative, 17520*time.Hour, "Relative time value since when in the past the CA certificate should be valid. The value has a time unit, the greatest time unit is h for hour.") + generateCaCmd.Flags().Duration(generateCANotAfterRelative, 17520*time.Hour, "Relative time value until when in the future the CA certificate should be valid. The value has a time unit, the greatest time unit is h for hour.") +} + +func runGenerateCA(cmd *cobra.Command, args []string) { + var certOutPath, curveName string + var notBefore, notAfter time.Duration + var err error + + if certOutPath, err = getStringFlag(generateCaCmd, generateCACertOutPath, logger); err != nil { + return + } + if curveName, err = getStringFlag(generateCaCmd, generateCACurveName, logger); err != nil { + return + } + if notBefore, err = getDurationFlag(generateCaCmd, generateCANotBeforeRelative, logger); err != nil { + return + } + if notAfter, err = getDurationFlag(generateCaCmd, generateCANotAfterRelative, logger); err != nil { + return + } + + logger, _ := logging.CreateLogger() + + logger = logger.With( + zap.String(generateCACurveName, curveName), + zap.String(generateCACertOutPath, certOutPath), + ) + + generator := cert.NewDefaultGenerator(cert.Options{ + CertCachePath: certOutPath, + Curve: cert.CurveType(curveName), + Validity: cert.ValidityByPurpose{ + CA: cert.ValidityDuration{ + NotAfterRelative: notAfter, + NotBeforeRelative: notBefore, + }, + }, + }) + + var caCrt *tls.Certificate + if caCrt, err = generator.CACert(caCertOptions); err != nil { + logger.Error( + "failed to generate CA certificate", + zap.Error(err), + ) + return + } + + if len(caCrt.Certificate) < 1 { + logger.Error("no public key given for generated CA certificate") + return + } + + var pubKey *x509.Certificate + if pubKey, err = x509.ParseCertificate(caCrt.Certificate[0]); err != nil { + logger.Error( + "failed to parse public key from generated CA", + zap.Error(err), + ) + return + } + + pemCrt := cert.NewPEM(caCrt) + if err = pemCrt.Write(pubKey.Subject.CommonName, certOutPath); err != nil { + logger.Error( + "failed to write Ca files", + zap.Error(err), + ) + } + logger.Info("completed certificate generation") +} + +func getDurationFlag(cmd *cobra.Command, flagName string, logger logging.Logger) (val time.Duration, err error) { + if val, err = cmd.Flags().GetDuration(flagName); err != nil { + logger.Error( + "failed to parse parse flag", + zap.String("flag", flagName), + zap.Error(err), + ) + } + return +} + +func getStringFlag(cmd *cobra.Command, flagName string, logger logging.Logger) (val string, err error) { + if val, err = cmd.Flags().GetString(flagName); err != nil { + logger.Error( + "failed to parse parse flag", + zap.String("flag", flagName), + zap.Error(err), + ) + } + return +} diff --git a/internal/cmd/init.go b/internal/cmd/init.go index eb8494a..f25c678 100644 --- a/internal/cmd/init.go +++ b/internal/cmd/init.go @@ -3,6 +3,7 @@ package cmd import ( "github.com/baez90/inetmock/internal/endpoints" "github.com/baez90/inetmock/internal/plugins" + "github.com/baez90/inetmock/pkg/api" "github.com/baez90/inetmock/pkg/logging" "github.com/baez90/inetmock/pkg/path" "github.com/spf13/viper" @@ -29,9 +30,8 @@ func initApp() (err error) { registry := plugins.Registry() endpointManager = endpoints.NewEndpointManager(logger) - if err = rootCmd.ParseFlags(os.Args); err != nil { - return - } + rootCmd.Flags().ParseErrorsWhitelist.UnknownFlags = false + _ = rootCmd.ParseFlags(os.Args) if err = appConfig.ReadConfig(configFilePath); err != nil { logger.Error( @@ -43,6 +43,14 @@ func initApp() (err error) { viperInst := viper.GetViper() pluginDir := viperInst.GetString("plugins-directory") + + if err = api.InitServices(viperInst, logger); err != nil { + logger.Error( + "failed to initialize app services", + zap.Error(err), + ) + } + pluginLoadStartTime := time.Now() if err = registry.LoadPlugins(pluginDir); err != nil { logger.Error("Failed to load plugins", diff --git a/internal/cmd/plugins.go b/internal/cmd/plugins.go index 09a1fbe..a4ef58d 100644 --- a/internal/cmd/plugins.go +++ b/internal/cmd/plugins.go @@ -18,5 +18,5 @@ The easiest way to explore what commands are available is to start with 'inetmoc This help page contains a list of available sub-commands starting with the name of the plugin as a prefix. `, } - rootCmd.AddCommand(pluginsCmd) + rootCmd.AddCommand(pluginsCmd, generateCaCmd) } diff --git a/internal/config/multi_handler_config.go b/internal/config/multi_handler_config.go index 6ea35a6..f1b9fdf 100644 --- a/internal/config/multi_handler_config.go +++ b/internal/config/multi_handler_config.go @@ -1,6 +1,7 @@ package config import ( + "github.com/baez90/inetmock/pkg/api" "github.com/spf13/viper" ) @@ -9,7 +10,7 @@ type MultiHandlerConfig interface { ListenAddress() string Ports() []uint16 Options() *viper.Viper - HandlerConfigs() []HandlerConfig + HandlerConfigs() []api.HandlerConfig } type multiHandlerConfig struct { @@ -39,10 +40,10 @@ func (m multiHandlerConfig) Options() *viper.Viper { return m.options } -func (m multiHandlerConfig) HandlerConfigs() []HandlerConfig { - configs := make([]HandlerConfig, 0) +func (m multiHandlerConfig) HandlerConfigs() []api.HandlerConfig { + configs := make([]api.HandlerConfig, 0) for _, port := range m.ports { - configs = append(configs, NewHandlerConfig(m.handlerName, port, m.listenAddress, m.options)) + configs = append(configs, api.NewHandlerConfig(m.handlerName, port, m.listenAddress, m.options)) } return configs } diff --git a/internal/config/multi_handler_config_test.go b/internal/config/multi_handler_config_test.go index 0d285e9..ce735fe 100644 --- a/internal/config/multi_handler_config_test.go +++ b/internal/config/multi_handler_config_test.go @@ -1,6 +1,7 @@ package config import ( + "github.com/baez90/inetmock/pkg/api" "github.com/spf13/viper" "reflect" "testing" @@ -16,12 +17,12 @@ func Test_multiHandlerConfig_HandlerConfigs(t *testing.T) { tests := []struct { name string fields fields - want []HandlerConfig + want []api.HandlerConfig }{ { name: "Get empty array if no ports are set", fields: fields{}, - want: make([]HandlerConfig, 0), + want: make([]api.HandlerConfig, 0), }, { name: "Get a single handler config if only one port is set", @@ -31,13 +32,8 @@ func Test_multiHandlerConfig_HandlerConfigs(t *testing.T) { listenAddress: "0.0.0.0", options: nil, }, - want: []HandlerConfig{ - &handlerConfig{ - handlerName: "sampleHandler", - port: 80, - listenAddress: "0.0.0.0", - options: nil, - }, + want: []api.HandlerConfig{ + api.NewHandlerConfig("sampleHandler", 80, "0.0.0.0", nil), }, }, { @@ -48,19 +44,9 @@ func Test_multiHandlerConfig_HandlerConfigs(t *testing.T) { listenAddress: "0.0.0.0", options: nil, }, - want: []HandlerConfig{ - &handlerConfig{ - handlerName: "sampleHandler", - port: 80, - listenAddress: "0.0.0.0", - options: nil, - }, - &handlerConfig{ - handlerName: "sampleHandler", - port: 8080, - listenAddress: "0.0.0.0", - options: nil, - }, + want: []api.HandlerConfig{ + api.NewHandlerConfig("sampleHandler", 80, "0.0.0.0", nil), + api.NewHandlerConfig("sampleHandler", 8080, "0.0.0.0", nil), }, }, } diff --git a/internal/config/parsing.go b/internal/config/parsing.go index adc4a09..ad85400 100644 --- a/internal/config/parsing.go +++ b/internal/config/parsing.go @@ -1,6 +1,15 @@ package config -import "github.com/spf13/viper" +import ( + "github.com/spf13/viper" +) + +const ( + pluginConfigKey = "handler" + listenAddressConfigKey = "listenAddress" + portConfigKey = "port" + portsConfigKey = "ports" +) func CreateMultiHandlerConfig(handlerConfig *viper.Viper) MultiHandlerConfig { return NewMultiHandlerConfig( diff --git a/internal/endpoints/endpoint.go b/internal/endpoints/endpoint.go index 0394e86..1cfd379 100644 --- a/internal/endpoints/endpoint.go +++ b/internal/endpoints/endpoint.go @@ -1,8 +1,7 @@ -//go:generate mockgen -source=endpoint.go -destination=./../../internal/mock/endpoint_mock.go -package=mock +//go:generate mockgen -source=endpoint.go -destination=./../../internal/mock/endpoints/endpoint_mock.go -package=endpoints_mock package endpoints import ( - "github.com/baez90/inetmock/internal/config" "github.com/baez90/inetmock/pkg/api" ) @@ -15,7 +14,7 @@ type Endpoint interface { type endpoint struct { name string handler api.ProtocolHandler - config config.HandlerConfig + config api.HandlerConfig } func (e endpoint) Name() string { diff --git a/internal/endpoints/endpoint_manager.go b/internal/endpoints/endpoint_manager.go index 209e3b7..907f868 100644 --- a/internal/endpoints/endpoint_manager.go +++ b/internal/endpoints/endpoint_manager.go @@ -40,19 +40,20 @@ func (e endpointManager) StartedEndpoints() []Endpoint { return e.properlyStartedEndpoints } -func (e *endpointManager) CreateEndpoint(name string, multiHandlerConfig config.MultiHandlerConfig) (err error) { - if handler, ok := e.registry.HandlerForName(multiHandlerConfig.HandlerName()); ok { - for _, handlerConfig := range multiHandlerConfig.HandlerConfigs() { +func (e *endpointManager) CreateEndpoint(name string, multiHandlerConfig config.MultiHandlerConfig) error { + for _, handlerConfig := range multiHandlerConfig.HandlerConfigs() { + if handler, ok := e.registry.HandlerForName(multiHandlerConfig.HandlerName()); ok { e.registeredEndpoints = append(e.registeredEndpoints, &endpoint{ name: name, handler: handler, config: handlerConfig, }) + } else { + return fmt.Errorf("no matching handler registered for names %s", multiHandlerConfig.HandlerName()) } - } else { - err = fmt.Errorf("no matching handler registered for name %s", multiHandlerConfig.HandlerName()) } - return + + return nil } func (e *endpointManager) StartEndpoints() { diff --git a/internal/endpoints/endpoint_manager_test.go b/internal/endpoints/endpoint_manager_test.go index 30a6668..3d0530a 100644 --- a/internal/endpoints/endpoint_manager_test.go +++ b/internal/endpoints/endpoint_manager_test.go @@ -2,7 +2,9 @@ package endpoints import ( "github.com/baez90/inetmock/internal/config" - "github.com/baez90/inetmock/internal/mock" + api_mock "github.com/baez90/inetmock/internal/mock/api" + logging_mock "github.com/baez90/inetmock/internal/mock/logging" + plugins_mock "github.com/baez90/inetmock/internal/mock/plugins" "github.com/baez90/inetmock/internal/plugins" "github.com/baez90/inetmock/pkg/logging" "github.com/golang/mock/gomock" @@ -33,18 +35,18 @@ func Test_endpointManager_CreateEndpoint(t *testing.T) { wantEndpoints: 1, fields: fields{ logger: func() logging.Logger { - return mock.NewMockLogger(gomock.NewController(t)) + return logging_mock.NewMockLogger(gomock.NewController(t)) }(), registeredEndpoints: nil, properlyStartedEndpoints: nil, registry: func() plugins.HandlerRegistry { - registry := mock.NewMockHandlerRegistry(gomock.NewController(t)) + registry := plugins_mock.NewMockHandlerRegistry(gomock.NewController(t)) registry. EXPECT(). HandlerForName("sampleHandler"). MinTimes(1). MaxTimes(1). - Return(mock.NewMockProtocolHandler(gomock.NewController(t)), true) + Return(api_mock.NewMockProtocolHandler(gomock.NewController(t)), true) return registry }(), }, @@ -64,12 +66,12 @@ func Test_endpointManager_CreateEndpoint(t *testing.T) { wantEndpoints: 0, fields: fields{ logger: func() logging.Logger { - return mock.NewMockLogger(gomock.NewController(t)) + return logging_mock.NewMockLogger(gomock.NewController(t)) }(), registeredEndpoints: nil, properlyStartedEndpoints: nil, registry: func() plugins.HandlerRegistry { - registry := mock.NewMockHandlerRegistry(gomock.NewController(t)) + registry := plugins_mock.NewMockHandlerRegistry(gomock.NewController(t)) registry. EXPECT(). HandlerForName("sampleHandler"). diff --git a/internal/endpoints/endpoint_test.go b/internal/endpoints/endpoint_test.go index 3b6e687..65e5d76 100644 --- a/internal/endpoints/endpoint_test.go +++ b/internal/endpoints/endpoint_test.go @@ -2,8 +2,7 @@ package endpoints import ( "fmt" - "github.com/baez90/inetmock/internal/config" - "github.com/baez90/inetmock/internal/mock" + api_mock "github.com/baez90/inetmock/internal/mock/api" "github.com/baez90/inetmock/pkg/api" "github.com/golang/mock/gomock" "testing" @@ -13,7 +12,7 @@ func Test_endpoint_Name(t *testing.T) { type fields struct { name string handler api.ProtocolHandler - config config.HandlerConfig + config api.HandlerConfig } tests := []struct { name string @@ -51,7 +50,7 @@ func Test_endpoint_Shutdown(t *testing.T) { type fields struct { name string handler api.ProtocolHandler - config config.HandlerConfig + config api.HandlerConfig } tests := []struct { name string @@ -62,7 +61,7 @@ func Test_endpoint_Shutdown(t *testing.T) { name: "Expect no error if mocked handler does not return one", fields: fields{ handler: func() api.ProtocolHandler { - handler := mock.NewMockProtocolHandler(gomock.NewController(t)) + handler := api_mock.NewMockProtocolHandler(gomock.NewController(t)) handler.EXPECT(). Shutdown(). MaxTimes(1). @@ -76,7 +75,7 @@ func Test_endpoint_Shutdown(t *testing.T) { name: "Expect error if mocked handler returns one", fields: fields{ handler: func() api.ProtocolHandler { - handler := mock.NewMockProtocolHandler(gomock.NewController(t)) + handler := api_mock.NewMockProtocolHandler(gomock.NewController(t)) handler.EXPECT(). Shutdown(). MaxTimes(1). @@ -103,7 +102,7 @@ func Test_endpoint_Shutdown(t *testing.T) { func Test_endpoint_Start(t *testing.T) { - demoHandlerConfig := config.NewHandlerConfig( + demoHandlerConfig := api.NewHandlerConfig( "sampleHandler", 80, "0.0.0.0", @@ -113,7 +112,7 @@ func Test_endpoint_Start(t *testing.T) { type fields struct { name string handler api.ProtocolHandler - config config.HandlerConfig + config api.HandlerConfig } tests := []struct { name string @@ -124,7 +123,7 @@ func Test_endpoint_Start(t *testing.T) { name: "Expect no error if mocked handler does not return one", fields: fields{ handler: func() api.ProtocolHandler { - handler := mock.NewMockProtocolHandler(gomock.NewController(t)) + handler := api_mock.NewMockProtocolHandler(gomock.NewController(t)) handler.EXPECT(). Start(nil). MaxTimes(1). @@ -138,7 +137,7 @@ func Test_endpoint_Start(t *testing.T) { name: "Expect error if mocked handler returns one", fields: fields{ handler: func() api.ProtocolHandler { - handler := mock.NewMockProtocolHandler(gomock.NewController(t)) + handler := api_mock.NewMockProtocolHandler(gomock.NewController(t)) handler.EXPECT(). Start(nil). MaxTimes(1). @@ -153,7 +152,7 @@ func Test_endpoint_Start(t *testing.T) { fields: fields{ config: demoHandlerConfig, handler: func() api.ProtocolHandler { - handler := mock.NewMockProtocolHandler(gomock.NewController(t)) + handler := api_mock.NewMockProtocolHandler(gomock.NewController(t)) handler.EXPECT(). Start(demoHandlerConfig). MaxTimes(1). diff --git a/internal/plugins/loading.go b/internal/plugins/loading.go index 4fcd376..52e5e03 100644 --- a/internal/plugins/loading.go +++ b/internal/plugins/loading.go @@ -1,4 +1,4 @@ -//go:generate mockgen -source=loading.go -destination=./../../internal/mock/handler_registry_mock.go -package=mock +//go:generate mockgen -source=loading.go -destination=./../../internal/mock/plugins/handler_registry_mock.go -package=plugins_mock package plugins import ( diff --git a/mock_config.yaml b/mock_config.yaml index ad98264..766d4ff 100644 --- a/mock_config.yaml +++ b/mock_config.yaml @@ -15,15 +15,15 @@ x-response-rules: &httpResponseRules - pattern: ".*" response: ./assets/fakeFiles/default.html -x-tls-options: &tlsOptions +tls: ecdsaCurve: P256 validity: ca: notBeforeRelative: 17520h notAfterRelative: 17520h - domain: - notBeforeRelative: 168h - notAfterRelative: 168h + server: + NotBeforeRelative: 168h + NotAfterRelative: 168h rootCaCert: publicKey: ./ca.pem privateKey: ./ca.key @@ -43,8 +43,9 @@ endpoints: listenAddress: 0.0.0.0 port: 3128 options: - fallback: notfound - <<: *httpResponseRules + target: + ipAddress: 127.0.0.1 + port: 80 httpsDowngrade: handler: tls_interceptor listenAddress: 0.0.0.0 @@ -52,7 +53,6 @@ endpoints: - 443 - 8443 options: - <<: *tlsOptions target: ipAddress: 127.0.0.1 port: 80 @@ -75,7 +75,6 @@ endpoints: listenAddress: 0.0.0.0 port: 853 options: - <<: *tlsOptions target: ipAddress: 127.0.0.1 port: 53 \ No newline at end of file diff --git a/internal/config/handler_config.go b/pkg/api/handler_config.go similarity index 82% rename from internal/config/handler_config.go rename to pkg/api/handler_config.go index cfeee30..4545a42 100644 --- a/internal/config/handler_config.go +++ b/pkg/api/handler_config.go @@ -1,14 +1,7 @@ -package config +package api import "github.com/spf13/viper" -const ( - pluginConfigKey = "handler" - listenAddressConfigKey = "listenAddress" - portConfigKey = "port" - portsConfigKey = "ports" -) - type HandlerConfig interface { HandlerName() string ListenAddress() string diff --git a/internal/config/handler_config_test.go b/pkg/api/handler_config_test.go similarity index 99% rename from internal/config/handler_config_test.go rename to pkg/api/handler_config_test.go index 838c5fd..23952cb 100644 --- a/internal/config/handler_config_test.go +++ b/pkg/api/handler_config_test.go @@ -1,4 +1,4 @@ -package config +package api import ( "github.com/spf13/viper" diff --git a/pkg/api/protocol_handler.go b/pkg/api/protocol_handler.go index 182133d..afb7b3e 100644 --- a/pkg/api/protocol_handler.go +++ b/pkg/api/protocol_handler.go @@ -1,8 +1,7 @@ -//go:generate mockgen -source=protocol_handler.go -destination=./../../internal/mock/protocol_handler_mock.go -package=mock +//go:generate mockgen -source=protocol_handler.go -destination=./../../internal/mock/api/protocol_handler_mock.go -package=api_mock package api import ( - "github.com/baez90/inetmock/internal/config" "go.uber.org/zap" ) @@ -11,6 +10,6 @@ type PluginInstanceFactory func() ProtocolHandler type LoggingFactory func() (*zap.Logger, error) type ProtocolHandler interface { - Start(config config.HandlerConfig) error + Start(config HandlerConfig) error Shutdown() error } diff --git a/pkg/api/services.go b/pkg/api/services.go new file mode 100644 index 0000000..996a76e --- /dev/null +++ b/pkg/api/services.go @@ -0,0 +1,41 @@ +package api + +import ( + "github.com/baez90/inetmock/pkg/cert" + "github.com/baez90/inetmock/pkg/logging" + "github.com/spf13/viper" +) + +var ( + svcs Services +) + +type Services interface { + CertStore() cert.Store +} + +type services struct { + certStore cert.Store +} + +func InitServices( + config *viper.Viper, + logger logging.Logger, +) error { + certStore, err := cert.NewDefaultStore(config, logger) + if err != nil { + return err + } + svcs = &services{ + certStore: certStore, + } + return nil +} + +func ServicesInstance() Services { + return svcs +} + +func (s *services) CertStore() cert.Store { + return s.certStore +} diff --git a/pkg/cert/addr_utils.go b/pkg/cert/addr_utils.go new file mode 100644 index 0000000..adf3211 --- /dev/null +++ b/pkg/cert/addr_utils.go @@ -0,0 +1,22 @@ +package cert + +import ( + "fmt" + "strings" +) + +func extractIPFromAddress(addr string) (ip string, err error) { + if idx := strings.LastIndex(addr, ":"); idx < 0 { + err = fmt.Errorf("addr %s does not match expected scheme :", addr) + + } else { + /* get IP part of address */ + ip = addr[0:idx] + + /* trim [ ] for IPv6 addresses */ + if ip[0] == '[' { + ip = ip[1 : len(ip)-1] + } + } + return +} diff --git a/plugins/tls_interceptor/addr_utils_test.go b/pkg/cert/addr_utils_test.go similarity index 98% rename from plugins/tls_interceptor/addr_utils_test.go rename to pkg/cert/addr_utils_test.go index 4a224aa..a8401e4 100644 --- a/plugins/tls_interceptor/addr_utils_test.go +++ b/pkg/cert/addr_utils_test.go @@ -1,4 +1,4 @@ -package main +package cert import "testing" diff --git a/pkg/cert/cache.go b/pkg/cert/cache.go new file mode 100644 index 0000000..64d6190 --- /dev/null +++ b/pkg/cert/cache.go @@ -0,0 +1,78 @@ +//go:generate mockgen -source=cache.go -destination=./../../internal/mock/cert/cert_cache_mock.go -package=cert_mock + +package cert + +import ( + "crypto/tls" + "crypto/x509" + "errors" +) + +type Cache interface { + Put(cert *tls.Certificate) error + Get(cn string) (*tls.Certificate, bool) +} + +func NewFileSystemCache(certCachePath string, source TimeSource) Cache { + return &fileSystemCache{ + certCachePath: certCachePath, + inMemCache: make(map[string]*tls.Certificate), + timeSource: source, + } +} + +type fileSystemCache struct { + certCachePath string + inMemCache map[string]*tls.Certificate + timeSource TimeSource +} + +func (f *fileSystemCache) Put(cert *tls.Certificate) (err error) { + if cert == nil { + err = errors.New("cert may not be nil") + return + } + var cn string + if len(cert.Certificate) > 0 { + if pubKey, err := x509.ParseCertificate(cert.Certificate[0]); err != nil { + return err + } else { + cn = pubKey.Subject.CommonName + } + + f.inMemCache[cn] = cert + pemCrt := NewPEM(cert) + err = pemCrt.Write(cn, f.certCachePath) + } else { + err = errors.New("no public key present for certificate") + } + return +} + +func (f *fileSystemCache) Get(cn string) (*tls.Certificate, bool) { + + if crt, ok := f.inMemCache[cn]; ok { + return crt, true + } + + pemCrt := NewPEM(nil) + if err := pemCrt.Read(cn, f.certCachePath); err != nil || pemCrt.Cert() == nil { + return nil, false + } + + x509Cert, err := x509.ParseCertificate(pemCrt.Cert().Certificate[0]) + if err == nil && !certShouldBeRenewed(f.timeSource, x509Cert) { + return pemCrt.Cert(), true + } + + return nil, false +} + +func certShouldBeRenewed(timeSource TimeSource, cert *x509.Certificate) bool { + lifetime := cert.NotAfter.Sub(cert.NotBefore) + // if the cert is closer to the end of the lifetime than lifetime/2 it should be renewed + if cert.NotAfter.Sub(timeSource.UTCNow()) < lifetime/4 { + return true + } + return false +} diff --git a/pkg/cert/cache_test.go b/pkg/cert/cache_test.go new file mode 100644 index 0000000..c23a7a7 --- /dev/null +++ b/pkg/cert/cache_test.go @@ -0,0 +1,299 @@ +package cert + +import ( + "crypto/tls" + "crypto/x509" + "fmt" + certmock "github.com/baez90/inetmock/internal/mock/cert" + "github.com/golang/mock/gomock" + "os" + "path" + "reflect" + "testing" + "time" +) + +const ( + cnLocalhost = "localhost" + caCN = "UnitTests" + serverRelativeValidity = 24 * time.Hour + caRelativeValidity = 168 * time.Hour +) + +var ( + serverCN = fmt.Sprintf("%s-%d", cnLocalhost, time.Now().Unix()) +) + +func Test_certShouldBeRenewed(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + type args struct { + timeSource TimeSource + cert *x509.Certificate + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "Expect cert should not be renewed right after creation", + args: args{ + timeSource: func() TimeSource { + tsMock := certmock.NewMockTimeSource(ctrl) + tsMock. + EXPECT(). + UTCNow(). + Return(time.Now().UTC()). + Times(1) + return tsMock + }(), + cert: &x509.Certificate{ + NotAfter: time.Now().UTC().Add(serverRelativeValidity), + NotBefore: time.Now().UTC().Add(-serverRelativeValidity), + }, + }, + want: false, + }, + { + name: "Expect cert should be renewed if the remaining lifetime is less than a quarter of the total lifetime", + args: args{ + timeSource: func() TimeSource { + tsMock := certmock.NewMockTimeSource(ctrl) + tsMock. + EXPECT(). + UTCNow(). + Return(time.Now().UTC().Add(serverRelativeValidity/2 + 1*time.Hour)). + Times(1) + return tsMock + }(), + cert: &x509.Certificate{ + NotAfter: time.Now().UTC().Add(serverRelativeValidity), + NotBefore: time.Now().UTC().Add(-serverRelativeValidity), + }, + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := certShouldBeRenewed(tt.args.timeSource, tt.args.cert); got != tt.want { + t.Errorf("certShouldBeRenewed() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_fileSystemCache_Get(t *testing.T) { + type fields struct { + certCachePath string + inMemCache map[string]*tls.Certificate + timeSource TimeSource + } + type args struct { + cn string + } + tests := []struct { + name string + fields fields + args args + wantOk bool + }{ + { + name: "Get a miss when no cert is present", + fields: fields{ + certCachePath: os.TempDir(), + inMemCache: make(map[string]*tls.Certificate), + timeSource: NewTimeSource(), + }, + args: args{ + cnLocalhost, + }, + wantOk: false, + }, + { + name: "Get a prepared certificate from the memory cache", + fields: func() fields { + certGen := setupCertGen() + + caCrt, _ := certGen.CACert(GenerationOptions{ + CommonName: caCN, + }) + + srvCrt, _ := certGen.ServerCert(GenerationOptions{ + CommonName: cnLocalhost, + }, caCrt) + + return fields{ + certCachePath: os.TempDir(), + inMemCache: map[string]*tls.Certificate{ + cnLocalhost: srvCrt, + }, + timeSource: NewTimeSource(), + } + }(), + args: args{ + cn: cnLocalhost, + }, + wantOk: true, + }, + { + name: "Get a prepared certificate from the file system", + fields: func() fields { + certGen := setupCertGen() + + caCrt, _ := certGen.CACert(GenerationOptions{ + CommonName: "INetMock", + }) + + srvCrt, _ := certGen.ServerCert(GenerationOptions{ + CommonName: serverCN, + }, caCrt) + + pem := NewPEM(srvCrt) + if err := pem.Write(serverCN, os.TempDir()); err != nil { + panic(err) + } + + t.Cleanup(func() { + for _, f := range []string{ + path.Join(os.TempDir(), fmt.Sprintf("%s.pem", serverCN)), + path.Join(os.TempDir(), fmt.Sprintf("%s.key", serverCN)), + } { + _ = os.Remove(f) + } + }) + + return fields{ + certCachePath: os.TempDir(), + inMemCache: make(map[string]*tls.Certificate), + timeSource: NewTimeSource(), + } + }(), + args: args{ + cn: serverCN, + }, + wantOk: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + f := &fileSystemCache{ + certCachePath: tt.fields.certCachePath, + inMemCache: tt.fields.inMemCache, + timeSource: tt.fields.timeSource, + } + gotCrt, gotOk := f.Get(tt.args.cn) + + if gotOk && (gotCrt == nil || !reflect.DeepEqual(reflect.TypeOf(new(tls.Certificate)), reflect.TypeOf(gotCrt))) { + t.Errorf("Wanted propert certificate but got %v", gotCrt) + } + + if gotOk != tt.wantOk { + t.Errorf("Get() gotOk = %v, want %v", gotOk, tt.wantOk) + } + }) + } +} + +func Test_fileSystemCache_Put(t *testing.T) { + type fields struct { + certCachePath string + inMemCache map[string]*tls.Certificate + timeSource TimeSource + } + type args struct { + cert *tls.Certificate + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "Want error if nil cert is passed to put", + fields: fields{ + certCachePath: os.TempDir(), + inMemCache: make(map[string]*tls.Certificate), + timeSource: NewTimeSource(), + }, + args: args{ + cert: nil, + }, + wantErr: true, + }, + { + name: "Want error if empty cert is passed to put", + fields: fields{ + certCachePath: os.TempDir(), + inMemCache: make(map[string]*tls.Certificate), + timeSource: NewTimeSource(), + }, + args: args{ + cert: &tls.Certificate{}, + }, + wantErr: true, + }, + { + name: "No error if valid cert is passed", + fields: fields{ + certCachePath: os.TempDir(), + inMemCache: make(map[string]*tls.Certificate), + timeSource: NewTimeSource(), + }, + args: args{ + cert: func() *tls.Certificate { + gen := setupCertGen() + ca, _ := gen.CACert(GenerationOptions{ + CommonName: caCN, + }) + + srvCN := fmt.Sprintf("%s-%d", cnLocalhost, time.Now().Unix()) + + t.Cleanup(func() { + for _, f := range []string{ + path.Join(os.TempDir(), fmt.Sprintf("%s.pem", srvCN)), + path.Join(os.TempDir(), fmt.Sprintf("%s.key", srvCN)), + } { + _ = os.Remove(f) + } + }) + + srvCrt, _ := gen.ServerCert(GenerationOptions{ + CommonName: srvCN, + }, ca) + return srvCrt + }(), + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + f := &fileSystemCache{ + certCachePath: tt.fields.certCachePath, + inMemCache: tt.fields.inMemCache, + timeSource: tt.fields.timeSource, + } + if err := f.Put(tt.args.cert); (err != nil) != tt.wantErr { + t.Errorf("Put() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func setupCertGen() Generator { + return NewDefaultGenerator(Options{ + Validity: ValidityByPurpose{ + Server: ValidityDuration{ + NotBeforeRelative: serverRelativeValidity, + NotAfterRelative: serverRelativeValidity, + }, + CA: ValidityDuration{ + NotBeforeRelative: caRelativeValidity, + NotAfterRelative: caRelativeValidity, + }, + }, + }) +} diff --git a/pkg/cert/constants.go b/pkg/cert/constants.go new file mode 100644 index 0000000..151158a --- /dev/null +++ b/pkg/cert/constants.go @@ -0,0 +1,21 @@ +package cert + +const ( + CurveTypeP224 CurveType = "P224" + CurveTypeP256 CurveType = "P256" + CurveTypeP384 CurveType = "P384" + CurveTypeP521 CurveType = "P521" + CurveTypeED25519 CurveType = "ED25519" + + defaultServerValidityDuration = "168h" + defaultCAValidityDuration = "17520h" + + certCachePathConfigKey = "tls.certCachePath" + ecdsaCurveConfigKey = "tls.ecdsaCurve" + publicKeyConfigKey = "tls.rootCaCert.publicKey" + privateKeyPathConfigKey = "tls.rootCaCert.privateKey" + caCertValidityNotBeforeKey = "tls.validity.ca.notBeforeRelative" + caCertValidityNotAfterKey = "tls.validity.ca.notAfterRelative" + serverCertValidityNotBeforeKey = "tls.validity.server.notBeforeRelative" + serverCertValidityNotAfterKey = "tls.validity.server.notAfterRelative" +) diff --git a/pkg/cert/defaults.go b/pkg/cert/defaults.go new file mode 100644 index 0000000..640d470 --- /dev/null +++ b/pkg/cert/defaults.go @@ -0,0 +1,43 @@ +package cert + +import ( + "github.com/baez90/inetmock/pkg/defaulting" + "reflect" +) + +var ( + certOptionsDefaulter defaulting.Defaulter = func(instance interface{}) { + switch o := instance.(type) { + case *GenerationOptions: + + if len(o.Country) < 1 { + o.Country = []string{"US"} + } + + if len(o.Locality) < 1 { + o.Locality = []string{"San Francisco"} + } + + if len(o.Organization) < 1 { + o.Organization = []string{"INetMock"} + } + + if len(o.StreetAddress) < 1 { + o.StreetAddress = []string{"Golden Gate Bridge"} + } + + if len(o.PostalCode) < 1 { + o.PostalCode = []string{"94016"} + } + + if len(o.Province) < 1 { + o.Province = []string{""} + } + } + } +) + +func init() { + certOptionsType := reflect.TypeOf(GenerationOptions{}) + defaulters.Register(certOptionsType, certOptionsDefaulter) +} diff --git a/pkg/cert/defaults_test.go b/pkg/cert/defaults_test.go new file mode 100644 index 0000000..e5cf2f5 --- /dev/null +++ b/pkg/cert/defaults_test.go @@ -0,0 +1,39 @@ +package cert + +import ( + "reflect" + "testing" +) + +func Test_certOptionsDefaulter(t *testing.T) { + tests := []struct { + name string + arg GenerationOptions + expected GenerationOptions + }{ + { + name: "", + arg: GenerationOptions{ + CommonName: "CA", + }, + expected: GenerationOptions{ + CommonName: "CA", + Country: []string{"US"}, + Locality: []string{"San Francisco"}, + Organization: []string{"INetMock"}, + StreetAddress: []string{"Golden Gate Bridge"}, + PostalCode: []string{"94016"}, + Province: []string{""}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + certOptionsDefaulter(&tt.arg) + if !reflect.DeepEqual(tt.expected, tt.arg) { + t.Errorf("Apply defaulter expected=%v got=%v", tt.expected, tt.arg) + } + }) + } +} diff --git a/pkg/cert/generator.go b/pkg/cert/generator.go new file mode 100644 index 0000000..411f921 --- /dev/null +++ b/pkg/cert/generator.go @@ -0,0 +1,184 @@ +package cert + +import ( + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "github.com/baez90/inetmock/pkg/defaulting" + "math/big" + "net" +) + +var ( + defaulters = defaulting.New() +) + +type GenerationOptions struct { + CommonName string + Organization []string + OrganizationalUnit []string + IPAddresses []net.IP + DNSNames []string + Country []string + Province []string + Locality []string + StreetAddress []string + PostalCode []string +} + +type Generator interface { + CACert(options GenerationOptions) (*tls.Certificate, error) + ServerCert(options GenerationOptions, ca *tls.Certificate) (*tls.Certificate, error) +} + +func NewDefaultGenerator(options Options) Generator { + return NewGenerator(options, NewTimeSource(), defaultKeyProvider(options)) +} + +func NewGenerator(options Options, source TimeSource, provider KeyProvider) Generator { + return &generator{ + options: options, + provider: provider, + timeSource: source, + } +} + +type generator struct { + options Options + provider KeyProvider + timeSource TimeSource + outDir string +} + +func (g *generator) privateKey() (key interface{}, err error) { + if g.provider != nil { + return g.provider() + } else { + return defaultKeyProvider(g.options)() + } +} + +func (g *generator) ServerCert(options GenerationOptions, ca *tls.Certificate) (cert *tls.Certificate, err error) { + defaulters.Apply(&options) + var serialNumber *big.Int + if serialNumber, err = generateSerialNumber(); err != nil { + return + } + + var privateKey interface{} + if privateKey, err = g.privateKey(); err != nil { + return + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + CommonName: options.CommonName, + Organization: options.Organization, + OrganizationalUnit: options.OrganizationalUnit, + Country: options.Country, + Province: options.Province, + Locality: options.Locality, + StreetAddress: options.StreetAddress, + PostalCode: options.PostalCode, + }, + IPAddresses: options.IPAddresses, + DNSNames: options.DNSNames, + NotBefore: g.timeSource.UTCNow().Add(-g.options.Validity.Server.NotBeforeRelative), + NotAfter: g.timeSource.UTCNow().Add(g.options.Validity.Server.NotAfterRelative), + KeyUsage: x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + } + var caCrt *x509.Certificate + caCrt, err = x509.ParseCertificate(ca.Certificate[0]) + + var derBytes []byte + if derBytes, err = x509.CreateCertificate(rand.Reader, &template, caCrt, publicKey(privateKey), ca.PrivateKey); err != nil { + return + } + + var privateKeyBytes []byte + if privateKeyBytes, err = x509.MarshalPKCS8PrivateKey(privateKey); err != nil { + return + } + + if cert, err = parseCert(derBytes, privateKeyBytes); err != nil { + return + } + + return +} + +func (g generator) CACert(options GenerationOptions) (crt *tls.Certificate, err error) { + defaulters.Apply(&options) + + var privateKey interface{} + var serialNumber *big.Int + if serialNumber, err = generateSerialNumber(); err != nil { + return + } + + if privateKey, err = g.privateKey(); err != nil { + return + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + CommonName: options.CommonName, + Organization: options.Organization, + Country: options.Country, + Province: options.Province, + Locality: options.Locality, + StreetAddress: options.StreetAddress, + PostalCode: options.PostalCode, + }, + IsCA: true, + NotBefore: g.timeSource.UTCNow().Add(-g.options.Validity.Server.NotBeforeRelative), + NotAfter: g.timeSource.UTCNow().Add(g.options.Validity.Server.NotAfterRelative), + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + var derBytes []byte + if derBytes, err = x509.CreateCertificate(rand.Reader, &template, &template, publicKey(privateKey), privateKey); err != nil { + return + } + + var privateKeyBytes []byte + if privateKeyBytes, err = x509.MarshalPKCS8PrivateKey(privateKey); err != nil { + return + } + + crt, err = parseCert(derBytes, privateKeyBytes) + + return +} + +func generateSerialNumber() (*big.Int, error) { + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + return rand.Int(rand.Reader, serialNumberLimit) +} + +func publicKey(privateKey interface{}) interface{} { + switch k := privateKey.(type) { + case *ecdsa.PrivateKey: + return &k.PublicKey + case ed25519.PrivateKey: + return k.Public().(ed25519.PublicKey) + default: + return nil + } +} + +func parseCert(derBytes []byte, privateKeyBytes []byte) (*tls.Certificate, error) { + pemEncodedPublicKey := pem.EncodeToMemory(&pem.Block{Type: certificateBlockType, Bytes: derBytes}) + pemEncodedPrivateKey := pem.EncodeToMemory(&pem.Block{Type: privateKeyBlockType, Bytes: privateKeyBytes}) + cert, err := tls.X509KeyPair(pemEncodedPublicKey, pemEncodedPrivateKey) + return &cert, err +} diff --git a/pkg/cert/options.go b/pkg/cert/options.go new file mode 100644 index 0000000..fa18280 --- /dev/null +++ b/pkg/cert/options.go @@ -0,0 +1,79 @@ +package cert + +import ( + "fmt" + "github.com/spf13/viper" + "os" + "strings" + "time" +) + +var ( + requiredConfigKeys = []string{ + publicKeyConfigKey, + privateKeyPathConfigKey, + } +) + +type CurveType string + +type File struct { + PublicKeyPath string + PrivateKeyPath string +} + +type ValidityDuration struct { + NotBeforeRelative time.Duration + NotAfterRelative time.Duration +} + +type ValidityByPurpose struct { + CA ValidityDuration + Server ValidityDuration +} + +type Options struct { + RootCACert File + CertCachePath string + Curve CurveType + Validity ValidityByPurpose +} + +func loadFromConfig(config *viper.Viper) (Options, error) { + missingKeys := make([]string, 0) + for _, requiredKey := range requiredConfigKeys { + if !config.IsSet(requiredKey) { + missingKeys = append(missingKeys, requiredKey) + } + } + + if len(missingKeys) > 0 { + return Options{}, fmt.Errorf("config keys are missing: %s", strings.Join(missingKeys, ", ")) + } + + config.SetDefault(certCachePathConfigKey, os.TempDir()) + config.SetDefault(ecdsaCurveConfigKey, string(CurveTypeED25519)) + config.SetDefault(caCertValidityNotBeforeKey, defaultCAValidityDuration) + config.SetDefault(caCertValidityNotAfterKey, defaultCAValidityDuration) + config.SetDefault(serverCertValidityNotBeforeKey, defaultServerValidityDuration) + config.SetDefault(serverCertValidityNotAfterKey, defaultServerValidityDuration) + + return Options{ + CertCachePath: config.GetString(certCachePathConfigKey), + Curve: CurveType(config.GetString(ecdsaCurveConfigKey)), + Validity: ValidityByPurpose{ + CA: ValidityDuration{ + NotBeforeRelative: config.GetDuration(caCertValidityNotBeforeKey), + NotAfterRelative: config.GetDuration(caCertValidityNotAfterKey), + }, + Server: ValidityDuration{ + NotBeforeRelative: config.GetDuration(serverCertValidityNotBeforeKey), + NotAfterRelative: config.GetDuration(serverCertValidityNotAfterKey), + }, + }, + RootCACert: File{ + PublicKeyPath: config.GetString(publicKeyConfigKey), + PrivateKeyPath: config.GetString(privateKeyPathConfigKey), + }, + }, nil +} diff --git a/pkg/cert/options_test.go b/pkg/cert/options_test.go new file mode 100644 index 0000000..f8bddb2 --- /dev/null +++ b/pkg/cert/options_test.go @@ -0,0 +1,137 @@ +package cert + +import ( + "github.com/spf13/viper" + "os" + "reflect" + "strings" + "testing" + "time" +) + +func readViper(cfg string) *viper.Viper { + vpr := viper.New() + vpr.SetConfigType("yaml") + if err := vpr.ReadConfig(strings.NewReader(cfg)); err != nil { + panic(err) + } + return vpr +} + +func Test_loadFromConfig(t *testing.T) { + type args struct { + config *viper.Viper + } + tests := []struct { + name string + args args + want Options + wantErr bool + }{ + { + name: "Parse valid TLS configuration", + wantErr: false, + args: args{ + config: readViper(` +tls: + ecdsaCurve: P256 + validity: + ca: + notBeforeRelative: 17520h + notAfterRelative: 17520h + server: + NotBeforeRelative: 168h + NotAfterRelative: 168h + rootCaCert: + publicKey: ./ca.pem + privateKey: ./ca.key + certCachePath: /tmp/inetmock/ +`), + }, + want: Options{ + RootCACert: File{ + PublicKeyPath: "./ca.pem", + PrivateKeyPath: "./ca.key", + }, + CertCachePath: "/tmp/inetmock/", + Curve: CurveTypeP256, + Validity: ValidityByPurpose{ + CA: ValidityDuration{ + NotBeforeRelative: 17520 * time.Hour, + NotAfterRelative: 17520 * time.Hour, + }, + Server: ValidityDuration{ + NotBeforeRelative: 168 * time.Hour, + NotAfterRelative: 168 * time.Hour, + }, + }, + }, + }, + { + name: "Get an error if CA public key path is missing", + args: args{ + readViper(` +tls: + rootCaCert: + privateKey: ./ca.key +`), + }, + want: Options{}, + wantErr: true, + }, + { + name: "Get an error if CA private key path is missing", + args: args{ + readViper(` +tls: + rootCaCert: + publicKey: ./ca.pem +`), + }, + want: Options{}, + wantErr: true, + }, + { + name: "Get default options if all required fields are set", + args: args{ + readViper(` +tls: + rootCaCert: + publicKey: ./ca.pem + privateKey: ./ca.key +`), + }, + want: Options{ + RootCACert: File{ + PublicKeyPath: "./ca.pem", + PrivateKeyPath: "./ca.key", + }, + CertCachePath: os.TempDir(), + Curve: CurveTypeED25519, + Validity: ValidityByPurpose{ + CA: ValidityDuration{ + NotBeforeRelative: 17520 * time.Hour, + NotAfterRelative: 17520 * time.Hour, + }, + Server: ValidityDuration{ + NotBeforeRelative: 168 * time.Hour, + NotAfterRelative: 168 * time.Hour, + }, + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := loadFromConfig(tt.args.config) + if (err != nil) != tt.wantErr { + t.Errorf("loadFromConfig() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("loadFromConfig() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/cert/pem.go b/pkg/cert/pem.go new file mode 100644 index 0000000..5b78d91 --- /dev/null +++ b/pkg/cert/pem.go @@ -0,0 +1,79 @@ +package cert + +import ( + "crypto/tls" + "crypto/x509" + "encoding/pem" + "errors" + "fmt" + "github.com/baez90/inetmock/pkg/path" + "os" + "path/filepath" +) + +const ( + certificateBlockType = "CERTIFICATE" + privateKeyBlockType = "PRIVATE KEY" +) + +type PEM interface { + Cert() *tls.Certificate + Write(cn string, outDir string) error + Read(cn string, inDir string) error + ReadFrom(pubKeyPath, privateKeyPath string) error +} + +func NewPEM(crt *tls.Certificate) PEM { + return &pemCrt{ + crt: crt, + } +} + +type pemCrt struct { + crt *tls.Certificate +} + +func (p *pemCrt) Cert() *tls.Certificate { + return p.crt +} + +func (p pemCrt) Write(cn string, outDir string) (err error) { + + var certOut *os.File + if certOut, err = os.Create(filepath.Join(outDir, fmt.Sprintf("%s.pem", cn))); err != nil { + return + } + defer certOut.Close() + if err = pem.Encode(certOut, &pem.Block{Type: certificateBlockType, Bytes: p.crt.Certificate[0]}); err != nil { + return + } + + var keyOut *os.File + if keyOut, err = os.OpenFile(filepath.Join(outDir, fmt.Sprintf("%s.key", cn)), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600); err != nil { + return + } + var privKeyBytes []byte + privKeyBytes, err = x509.MarshalPKCS8PrivateKey(p.crt.PrivateKey) + err = pem.Encode(keyOut, &pem.Block{Type: privateKeyBlockType, Bytes: privKeyBytes}) + return +} + +func (p *pemCrt) Read(cn string, inDir string) error { + certPath := filepath.Join(inDir, fmt.Sprintf("%s.pem", cn)) + keyPath := filepath.Join(inDir, fmt.Sprintf("%s.key", cn)) + + return p.ReadFrom(certPath, keyPath) +} + +func (p *pemCrt) ReadFrom(pubKeyPath, privateKeyPath string) (err error) { + var tlsCrt tls.Certificate + if path.FileExists(pubKeyPath) && path.FileExists(privateKeyPath) { + if tlsCrt, err = tls.LoadX509KeyPair(pubKeyPath, privateKeyPath); err == nil { + p.crt = &tlsCrt + } + } else { + err = errors.New("either public or private key file do not exist") + } + + return +} diff --git a/pkg/cert/store.go b/pkg/cert/store.go new file mode 100644 index 0000000..9943cfc --- /dev/null +++ b/pkg/cert/store.go @@ -0,0 +1,153 @@ +package cert + +import ( + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "github.com/baez90/inetmock/pkg/logging" + "github.com/spf13/viper" + "go.uber.org/zap" + "net" +) + +const ( + ipv4Loopback = "127.0.0.1" +) + +var ( + defaultKeyProvider = func(options Options) func() (key interface{}, err error) { + return func() (key interface{}, err error) { + return privateKeyForCurve(options) + } + } +) + +type KeyProvider func() (key interface{}, err error) + +type Store interface { + CACert() *tls.Certificate + GetCertificate(serverName string, ip string) (*tls.Certificate, error) + TLSConfig() *tls.Config +} + +func NewDefaultStore( + config *viper.Viper, + logger logging.Logger, +) (Store, error) { + options, err := loadFromConfig(config) + if err != nil { + return nil, err + } + timeSource := NewTimeSource() + return NewStore( + options, + NewFileSystemCache(options.CertCachePath, timeSource), + NewDefaultGenerator(options), + logger, + ) +} + +func NewStore( + options Options, + cache Cache, + generator Generator, + logger logging.Logger, +) (Store, error) { + store := &store{ + options: options, + cache: cache, + generator: generator, + logger: logger, + } + + if err := store.loadCACert(); err != nil { + return nil, err + } + + return store, nil +} + +type store struct { + options Options + caCert *tls.Certificate + cache Cache + timeSource TimeSource + generator Generator + logger logging.Logger +} + +func (s *store) TLSConfig() *tls.Config { + rootCaPool := x509.NewCertPool() + rootCaPubKey, _ := x509.ParseCertificate(s.caCert.Certificate[0]) + rootCaPool.AddCert(rootCaPubKey) + + return &tls.Config{ + GetCertificate: func(info *tls.ClientHelloInfo) (cert *tls.Certificate, err error) { + var localIp string + if localIp, err = extractIPFromAddress(info.Conn.LocalAddr().String()); err != nil { + localIp = ipv4Loopback + } + + if cert, err = s.GetCertificate(info.ServerName, localIp); err != nil { + s.logger.Error( + "error while resolving certificate", + zap.String("serverName", info.ServerName), + zap.String("localAddr", localIp), + zap.Error(err), + ) + } + + return + }, + RootCAs: rootCaPool, + } +} + +func (s *store) loadCACert() (err error) { + pemCrt := NewPEM(nil) + if err = pemCrt.ReadFrom(s.options.RootCACert.PublicKeyPath, s.options.RootCACert.PrivateKeyPath); err != nil { + return + } + s.caCert = pemCrt.Cert() + return +} + +func (s *store) CACert() *tls.Certificate { + return s.caCert +} + +func (s *store) GetCertificate(serverName string, ip string) (cert *tls.Certificate, err error) { + if crt, ok := s.cache.Get(serverName); ok { + return crt, nil + } + + if cert, err = s.generator.ServerCert(GenerationOptions{ + CommonName: serverName, + DNSNames: []string{serverName}, + IPAddresses: []net.IP{net.ParseIP(ip)}, + }, s.caCert); err == nil { + s.cache.Put(cert) + } + + return +} + +func privateKeyForCurve(options Options) (privateKey interface{}, err error) { + switch options.Curve { + case CurveTypeP224: + privateKey, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader) + case CurveTypeP256: + privateKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + case CurveTypeP384: + privateKey, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) + case CurveTypeP521: + privateKey, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) + default: + _, privateKey, err = ed25519.GenerateKey(rand.Reader) + } + + return +} diff --git a/pkg/cert/time_source.go b/pkg/cert/time_source.go new file mode 100644 index 0000000..11c11f4 --- /dev/null +++ b/pkg/cert/time_source.go @@ -0,0 +1,20 @@ +//go:generate mockgen -source=time_source.go -destination=./../../internal/mock/cert/time_source_mock.go -package=cert_mock + +package cert + +import "time" + +type TimeSource interface { + UTCNow() time.Time +} + +func NewTimeSource() TimeSource { + return &defaultTimeSource{} +} + +type defaultTimeSource struct { +} + +func (d defaultTimeSource) UTCNow() time.Time { + return time.Now().UTC() +} diff --git a/pkg/defaulting/defaulter.go b/pkg/defaulting/defaulter.go new file mode 100644 index 0000000..4944935 --- /dev/null +++ b/pkg/defaulting/defaulter.go @@ -0,0 +1,43 @@ +package defaulting + +import ( + "reflect" +) + +type Defaulter func(instance interface{}) + +type Registry interface { + Register(t reflect.Type, defaulter ...Defaulter) + Apply(instance interface{}) +} + +func New() Registry { + return ®istry{ + defaulters: make(map[reflect.Type][]Defaulter), + } +} + +type registry struct { + defaulters map[reflect.Type][]Defaulter +} + +func (r *registry) Register(t reflect.Type, defaulter ...Defaulter) { + var given []Defaulter + if r, ok := r.defaulters[t]; ok { + given = r + } + + for _, d := range defaulter { + given = append(given, d) + } + + r.defaulters[t] = given +} + +func (r *registry) Apply(instance interface{}) { + if defs, ok := r.defaulters[reflect.TypeOf(instance)]; ok { + for _, def := range defs { + def(instance) + } + } +} diff --git a/pkg/defaulting/defaulter_test.go b/pkg/defaulting/defaulter_test.go new file mode 100644 index 0000000..d9b23c2 --- /dev/null +++ b/pkg/defaulting/defaulter_test.go @@ -0,0 +1,111 @@ +package defaulting + +import ( + "reflect" + "testing" +) + +func Test_registry_Apply(t *testing.T) { + type sample struct { + i int + } + type fields struct { + defaulters map[reflect.Type][]Defaulter + } + type args struct { + instance interface{} + } + type expect struct { + result interface{} + } + tests := []struct { + name string + fields fields + args args + expect expect + }{ + { + name: "Expect setting a sample value", + fields: fields{ + defaulters: map[reflect.Type][]Defaulter{ + reflect.TypeOf(&sample{}): {func(instance interface{}) { + switch i := instance.(type) { + case *sample: + i.i = 42 + } + }}, + }, + }, + args: args{ + instance: &sample{}, + }, + expect: expect{ + result: &sample{ + i: 42, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := ®istry{ + defaulters: tt.fields.defaulters, + } + + r.Apply(tt.args.instance) + + if !reflect.DeepEqual(tt.expect.result, tt.args.instance) { + t.Errorf("Apply() expected = %v got %v", tt.args.instance, tt.expect.result) + } + }) + } +} + +func Test_registry_Register(t *testing.T) { + type sample struct { + } + type fields struct { + defaulters map[reflect.Type][]Defaulter + } + type args struct { + t reflect.Type + defaulter []Defaulter + } + type expect struct { + length int + } + tests := []struct { + name string + fields fields + args args + expect expect + }{ + { + name: "", + fields: fields{ + defaulters: make(map[reflect.Type][]Defaulter), + }, + args: args{ + t: reflect.TypeOf(sample{}), + defaulter: []Defaulter{func(instance interface{}) { + + }}, + }, + expect: expect{ + length: 1, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := ®istry{ + defaulters: tt.fields.defaulters, + } + r.Register(tt.args.t, tt.args.defaulter...) + + if length := len(r.defaulters); length != tt.expect.length { + t.Errorf("len(r.defaulters) expect %d got %d", tt.expect.length, length) + } + }) + } +} diff --git a/pkg/logging/logger.go b/pkg/logging/logger.go index 22f4be9..6665b11 100644 --- a/pkg/logging/logger.go +++ b/pkg/logging/logger.go @@ -1,4 +1,4 @@ -//go:generate mockgen -source=logger.go -destination=./../../internal/mock/logger_mock.go -package=mock +//go:generate mockgen -source=logger.go -destination=./../../internal/mock/logging/logger_mock.go -package=logging_mock package logging import "go.uber.org/zap" diff --git a/plugins/dns_mock/go.mod b/plugins/dns_mock/go.mod index f02f77c..8d1949e 100644 --- a/plugins/dns_mock/go.mod +++ b/plugins/dns_mock/go.mod @@ -6,7 +6,7 @@ require ( github.com/baez90/inetmock v0.0.1 github.com/miekg/dns v1.1.29 github.com/spf13/viper v1.6.3 - go.uber.org/zap v1.14.1 + go.uber.org/zap v1.15.0 golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 // indirect golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect ) diff --git a/plugins/dns_mock/go.sum b/plugins/dns_mock/go.sum index 689d313..93b9c75 100644 --- a/plugins/dns_mock/go.sum +++ b/plugins/dns_mock/go.sum @@ -149,6 +149,8 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -188,6 +190,8 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= diff --git a/plugins/dns_mock/main.go b/plugins/dns_mock/main.go index 6b1ff1c..a4ae9fa 100644 --- a/plugins/dns_mock/main.go +++ b/plugins/dns_mock/main.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "github.com/baez90/inetmock/internal/config" + "github.com/baez90/inetmock/pkg/api" "github.com/baez90/inetmock/pkg/logging" "github.com/miekg/dns" "go.uber.org/zap" @@ -13,7 +13,7 @@ type dnsHandler struct { dnsServer []*dns.Server } -func (d *dnsHandler) Start(config config.HandlerConfig) (err error) { +func (d *dnsHandler) Start(config api.HandlerConfig) (err error) { options := loadFromConfig(config.Options()) addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) diff --git a/plugins/http_mock/go.mod b/plugins/http_mock/go.mod index a734142..b3ba23e 100644 --- a/plugins/http_mock/go.mod +++ b/plugins/http_mock/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( github.com/baez90/inetmock v0.0.1 github.com/spf13/viper v1.6.3 - go.uber.org/zap v1.14.1 + go.uber.org/zap v1.15.0 ) replace github.com/baez90/inetmock v0.0.1 => ../../ diff --git a/plugins/http_mock/go.sum b/plugins/http_mock/go.sum index 0495479..e310cb9 100644 --- a/plugins/http_mock/go.sum +++ b/plugins/http_mock/go.sum @@ -147,6 +147,8 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -178,6 +180,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= diff --git a/plugins/http_mock/main.go b/plugins/http_mock/main.go index 27a1362..bdf5ce5 100644 --- a/plugins/http_mock/main.go +++ b/plugins/http_mock/main.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "github.com/baez90/inetmock/internal/config" + "github.com/baez90/inetmock/pkg/api" "github.com/baez90/inetmock/pkg/logging" "go.uber.org/zap" "net/http" @@ -18,7 +18,7 @@ type httpHandler struct { server *http.Server } -func (p *httpHandler) Start(config config.HandlerConfig) (err error) { +func (p *httpHandler) Start(config api.HandlerConfig) (err error) { options := loadFromConfig(config.Options()) addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) p.server = &http.Server{Addr: addr, Handler: p.router} diff --git a/plugins/http_proxy/fallback.go b/plugins/http_proxy/fallback.go deleted file mode 100644 index 6cd87f4..0000000 --- a/plugins/http_proxy/fallback.go +++ /dev/null @@ -1,53 +0,0 @@ -package main - -import ( - "gopkg.in/elazarl/goproxy.v1" - "net/http" -) - -const ( - passthroughStrategyName = "passthrough" - notFoundStrategyName = "notfound" -) - -var ( - fallbackStrategies map[string]ProxyFallbackStrategy -) - -func init() { - fallbackStrategies = map[string]ProxyFallbackStrategy{ - passthroughStrategyName: &passThroughFallbackStrategy{}, - notFoundStrategyName: ¬FoundFallbackStrategy{}, - } -} - -func StrategyForName(name string) ProxyFallbackStrategy { - if strategy, ok := fallbackStrategies[name]; ok { - return strategy - } - return fallbackStrategies[notFoundStrategyName] -} - -type ProxyFallbackStrategy interface { - Apply(request *http.Request) (*http.Response, error) -} - -type passThroughFallbackStrategy struct { -} - -func (p passThroughFallbackStrategy) Apply(request *http.Request) (*http.Response, error) { - return nil, nil -} - -type notFoundFallbackStrategy struct { -} - -func (n notFoundFallbackStrategy) Apply(request *http.Request) (response *http.Response, err error) { - response = goproxy.NewResponse( - request, - goproxy.ContentTypeText, - http.StatusNotFound, - "The requested resource was not found", - ) - return -} diff --git a/plugins/http_proxy/fallback_test.go b/plugins/http_proxy/fallback_test.go deleted file mode 100644 index 09bf015..0000000 --- a/plugins/http_proxy/fallback_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "reflect" - "testing" -) - -func TestStrategyForName(t *testing.T) { - type args struct { - name string - } - tests := []struct { - name string - args args - want reflect.Type - }{ - { - name: "Test get notfound strategy", - want: reflect.TypeOf(¬FoundFallbackStrategy{}), - args: args{ - name: "notfound", - }, - }, - { - name: "Test get pass through strategy", - want: reflect.TypeOf(&passThroughFallbackStrategy{}), - args: args{ - name: "passthrough", - }, - }, - { - name: "Test get fallback strategy notfound because key is not known", - want: reflect.TypeOf(¬FoundFallbackStrategy{}), - args: args{ - name: "asdf12234", - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := StrategyForName(tt.args.name); reflect.TypeOf(got) != tt.want { - t.Errorf("StrategyForName() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/plugins/http_proxy/go.mod b/plugins/http_proxy/go.mod index c592bcb..b1429d7 100644 --- a/plugins/http_proxy/go.mod +++ b/plugins/http_proxy/go.mod @@ -4,9 +4,8 @@ go 1.14 require ( github.com/baez90/inetmock v0.0.1 - github.com/elazarl/goproxy v0.0.0-20200315184450-1f3cb6622dad github.com/spf13/viper v1.6.3 - go.uber.org/zap v1.14.1 + go.uber.org/zap v1.15.0 gopkg.in/elazarl/goproxy.v1 v1.0.0-20180725130230-947c36da3153 ) diff --git a/plugins/http_proxy/go.sum b/plugins/http_proxy/go.sum index 0703ef9..8d85c95 100644 --- a/plugins/http_proxy/go.sum +++ b/plugins/http_proxy/go.sum @@ -152,6 +152,8 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -183,6 +185,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= diff --git a/plugins/http_proxy/main.go b/plugins/http_proxy/main.go index 0176053..15678c9 100644 --- a/plugins/http_proxy/main.go +++ b/plugins/http_proxy/main.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "github.com/baez90/inetmock/internal/config" + "github.com/baez90/inetmock/pkg/api" "github.com/baez90/inetmock/pkg/logging" "go.uber.org/zap" "gopkg.in/elazarl/goproxy.v1" @@ -19,7 +19,7 @@ type httpProxy struct { server *http.Server } -func (h *httpProxy) Start(config config.HandlerConfig) (err error) { +func (h *httpProxy) Start(config api.HandlerConfig) (err error) { options := loadFromConfig(config.Options()) addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) h.server = &http.Server{Addr: addr, Handler: h.proxy} @@ -27,11 +27,20 @@ func (h *httpProxy) Start(config config.HandlerConfig) (err error) { zap.String("address", addr), ) + tlsConfig := api.ServicesInstance().CertStore().TLSConfig() + proxyHandler := &proxyHttpHandler{ options: options, logger: h.logger, } + + proxyHttpsHandler := &proxyHttpsHandler{ + tlsConfig: tlsConfig, + logger: h.logger, + } + h.proxy.OnRequest().Do(proxyHandler) + h.proxy.OnRequest().HandleConnect(proxyHttpsHandler) go h.startProxy() return } diff --git a/plugins/http_proxy/protocol_options.go b/plugins/http_proxy/protocol_options.go index 751c1ba..a31c3b3 100644 --- a/plugins/http_proxy/protocol_options.go +++ b/plugins/http_proxy/protocol_options.go @@ -1,52 +1,42 @@ package main import ( + "fmt" "github.com/spf13/viper" - "regexp" ) const ( - rulesConfigKey = "rules" - patternConfigKey = "pattern" - responseConfigKey = "response" - fallbackStrategyConfigKey = "fallback" + targetSchemeConfigKey = "target.scheme" + targetIpAddressConfigKey = "target.ipAddress" + targetPortConfigKey = "target.port" ) -type targetRule struct { - pattern *regexp.Regexp - response string +type redirectionTarget struct { + scheme string + ipAddress string + port uint16 } -func (tr targetRule) Pattern() *regexp.Regexp { - return tr.pattern -} - -func (tr targetRule) Response() string { - return tr.response +func (rt redirectionTarget) host() string { + return fmt.Sprintf("%s:%d", rt.ipAddress, rt.port) } type httpProxyOptions struct { - Rules []targetRule - FallbackStrategy ProxyFallbackStrategy + redirectionTarget redirectionTarget } func loadFromConfig(config *viper.Viper) (options httpProxyOptions) { - options.FallbackStrategy = StrategyForName(config.GetString(fallbackStrategyConfigKey)) - anonRules := config.Get(rulesConfigKey).([]interface{}) + config.SetDefault(targetSchemeConfigKey, "http") + config.SetDefault(targetIpAddressConfigKey, "127.0.0.1") + config.SetDefault(targetPortConfigKey, "80") - for _, i := range anonRules { - innerData := i.(map[interface{}]interface{}) - - if rulePattern, err := regexp.Compile(innerData[patternConfigKey].(string)); err == nil { - options.Rules = append(options.Rules, targetRule{ - pattern: rulePattern, - response: innerData[responseConfigKey].(string), - }) - } else { - panic(err) - } + options = httpProxyOptions{ + redirectionTarget{ + scheme: config.GetString(targetSchemeConfigKey), + ipAddress: config.GetString(targetIpAddressConfigKey), + port: uint16(config.GetInt(targetPortConfigKey)), + }, } - return } diff --git a/plugins/http_proxy/protocol_options_test.go b/plugins/http_proxy/protocol_options_test.go index b706998..06ab7d0 100644 --- a/plugins/http_proxy/protocol_options_test.go +++ b/plugins/http_proxy/protocol_options_test.go @@ -1,126 +1 @@ package main - -import ( - "bytes" - "github.com/spf13/viper" - "reflect" - "regexp" - "testing" -) - -func Test_loadFromConfig(t *testing.T) { - type args struct { - config string - } - tests := []struct { - name string - args args - wantOptions httpProxyOptions - }{ - { - name: "Parse proper configuration with notfound strategy", - args: args{ - config: ` -fallback: notfound, -rules: - - pattern: ".*" - response: ./assets/fakeFiles/default.html -`, - }, - wantOptions: httpProxyOptions{ - FallbackStrategy: StrategyForName(notFoundStrategyName), - Rules: []targetRule{ - { - response: "./assets/fakeFiles/default.html", - pattern: regexp.MustCompile(".*"), - }, - }, - }, - }, - { - name: "Parse proper configuration with pass through strategy", - args: args{ - config: ` -fallback: passthrough -rules: - - pattern: ".*" - response: ./assets/fakeFiles/default.html -`, - }, - wantOptions: httpProxyOptions{ - FallbackStrategy: StrategyForName(passthroughStrategyName), - Rules: []targetRule{ - { - response: "./assets/fakeFiles/default.html", - pattern: regexp.MustCompile(".*"), - }, - }, - }, - }, - { - name: "Parse proper configuration and preserve order of rules", - args: args{ - config: ` -fallback: notfound -rules: - - pattern: ".*\\.(?i)txt" - response: ./assets/fakeFiles/default.txt - - pattern: ".*" - response: ./assets/fakeFiles/default.html -`, - }, - wantOptions: httpProxyOptions{ - FallbackStrategy: StrategyForName(notFoundStrategyName), - Rules: []targetRule{ - { - response: "./assets/fakeFiles/default.txt", - pattern: regexp.MustCompile(".*\\.(?i)txt"), - }, - { - response: "./assets/fakeFiles/default.html", - pattern: regexp.MustCompile(".*"), - }, - }, - }, - }, - { - name: "Parse configuration with non existing fallback strategy key - falling back to 'notfound'", - args: args{ - config: ` -fallback: doesNotExist -rules: [] -`, - }, - wantOptions: httpProxyOptions{ - FallbackStrategy: StrategyForName(notFoundStrategyName), - Rules: nil, - }, - }, - { - name: "Parse configuration without any fallback key", - args: args{ - config: ` -f4llb4ck: doesNotExist -rules: [] -`, - }, - wantOptions: httpProxyOptions{ - FallbackStrategy: StrategyForName(notFoundStrategyName), - Rules: nil, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - config := viper.New() - config.SetConfigType("yaml") - if err := config.ReadConfig(bytes.NewBufferString(tt.args.config)); err != nil { - t.Errorf("failed to read config %v", err) - return - } - if gotOptions := loadFromConfig(config); !reflect.DeepEqual(gotOptions, tt.wantOptions) { - t.Errorf("loadFromConfig() = %v, want %v", gotOptions, tt.wantOptions) - } - }) - } -} diff --git a/plugins/http_proxy/proxy_handler.go b/plugins/http_proxy/proxy_handler.go index 55a6e8c..d77cad2 100644 --- a/plugins/http_proxy/proxy_handler.go +++ b/plugins/http_proxy/proxy_handler.go @@ -1,14 +1,13 @@ package main import ( + "context" + "crypto/tls" "github.com/baez90/inetmock/pkg/logging" "go.uber.org/zap" "gopkg.in/elazarl/goproxy.v1" - "io" - "mime" "net/http" - "os" - "path/filepath" + "net/url" ) type proxyHttpHandler struct { @@ -16,25 +15,27 @@ type proxyHttpHandler struct { logger logging.Logger } -/* -TODO implement HTTPS proxy like in TLS interceptor -func (p *proxyHttpHandler) HandleConnect(req string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) { +type proxyHttpsHandler struct { + tlsConfig *tls.Config + logger logging.Logger +} + +func (p *proxyHttpsHandler) HandleConnect(req string, _ *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) { + p.logger.Info( + "Intercepting HTTPS proxy request", + zap.String("request", req), + ) + return &goproxy.ConnectAction{ - Action: goproxy.OkConnect, - + Action: goproxy.ConnectMitm, + TLSConfig: func(host string, ctx *goproxy.ProxyCtx) (*tls.Config, error) { + return p.tlsConfig, nil + }, }, "" -}*/ - -func (p *proxyHttpHandler) Handle(req *http.Request, _ *goproxy.ProxyCtx) (retReq *http.Request, resp *http.Response) { +} +func (p *proxyHttpHandler) Handle(req *http.Request, ctx *goproxy.ProxyCtx) (retReq *http.Request, resp *http.Response) { retReq = req - resp = &http.Response{ - Request: req, - TransferEncoding: req.TransferEncoding, - Header: make(http.Header), - StatusCode: http.StatusOK, - } - p.logger.Info( "Handling request", zap.String("source", req.RemoteAddr), @@ -45,56 +46,48 @@ func (p *proxyHttpHandler) Handle(req *http.Request, _ *goproxy.ProxyCtx) (retRe zap.Reflect("headers", req.Header), ) - for _, rule := range p.options.Rules { - if rule.pattern.MatchString(req.URL.Path) { - if file, err := os.Open(rule.response); err != nil { - p.logger.Error( - "failed to open response target file", - zap.String("resonse", rule.response), - zap.Error(err), - ) - continue - } else { - resp.Body = file - - if stat, err := file.Stat(); err == nil { - resp.ContentLength = stat.Size() - } - - if contentType, err := GetContentType(rule, file); err == nil { - resp.Header["Content-Type"] = []string{contentType} - } - - p.logger.Info("returning fake response from rules") - return req, resp - } - } - } - - if resp, err := p.options.FallbackStrategy.Apply(req); err != nil { + var err error + if resp, err = ctx.RoundTrip(p.redirectHTTPRequest(req)); err != nil { p.logger.Error( - "failed to apply fallback strategy", + "error while doing roundtrip", zap.Error(err), ) - } else { - p.logger.Info("returning fake response from fallback strategy") - return req, resp + return req, nil } - p.logger.Info("falling back to proxying request through") - return req, nil -} - -func GetContentType(rule targetRule, file *os.File) (contentType string, err error) { - if contentType = mime.TypeByExtension(filepath.Ext(rule.response)); contentType != "" { - return - } - - var buf [512]byte - - n, _ := io.ReadFull(file, buf[:]) - - contentType = http.DetectContentType(buf[:n]) - _, err = file.Seek(0, io.SeekStart) + return +} + +func (p proxyHttpHandler) redirectHTTPRequest(originalRequest *http.Request) (redirectReq *http.Request) { + redirectReq = &http.Request{ + Method: originalRequest.Method, + URL: &url.URL{ + Host: p.options.redirectionTarget.host(), + Scheme: p.options.redirectionTarget.scheme, + Path: originalRequest.URL.Path, + ForceQuery: originalRequest.URL.ForceQuery, + Fragment: originalRequest.URL.Fragment, + Opaque: originalRequest.URL.Opaque, + RawPath: originalRequest.URL.RawPath, + RawQuery: originalRequest.URL.RawQuery, + User: originalRequest.URL.User, + }, + Proto: originalRequest.Proto, + ProtoMajor: originalRequest.ProtoMajor, + ProtoMinor: originalRequest.ProtoMinor, + Header: originalRequest.Header, + Body: originalRequest.Body, + GetBody: originalRequest.GetBody, + ContentLength: originalRequest.ContentLength, + TransferEncoding: originalRequest.TransferEncoding, + Close: false, + Host: originalRequest.Host, + Form: originalRequest.Form, + PostForm: originalRequest.PostForm, + MultipartForm: originalRequest.MultipartForm, + Trailer: originalRequest.Trailer, + } + redirectReq = redirectReq.WithContext(context.Background()) + return } diff --git a/plugins/tls_interceptor/addr_utils.go b/plugins/tls_interceptor/addr_utils.go deleted file mode 100644 index db39271..0000000 --- a/plugins/tls_interceptor/addr_utils.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -import ( - "fmt" - "regexp" - "strings" -) - -var ( - ipExtractionRegex = regexp.MustCompile(`(.+):\d{1,5}$`) -) - -func extractIPFromAddress(addr string) (string, error) { - matches := ipExtractionRegex.FindAllStringSubmatch(addr, -1) - if len(matches) > 0 && len(matches[0]) >= 1 { - return strings.Trim(matches[0][1], "[]"), nil - } else { - return "", fmt.Errorf("failed to extract IP address from addr %s", addr) - } -} diff --git a/plugins/tls_interceptor/cert_store.go b/plugins/tls_interceptor/cert_store.go deleted file mode 100644 index 229348d..0000000 --- a/plugins/tls_interceptor/cert_store.go +++ /dev/null @@ -1,204 +0,0 @@ -package main - -import ( - "crypto/rand" - "crypto/tls" - "crypto/x509" - "crypto/x509/pkix" - "fmt" - "github.com/baez90/inetmock/pkg/logging" - "github.com/baez90/inetmock/pkg/path" - "go.uber.org/zap" - "math/big" - "net" - "path/filepath" -) - -type keyProvider func() (key interface{}, err error) - -type certStore struct { - options *tlsOptions - keyProvider keyProvider - caCert *x509.Certificate - caPrivateKey interface{} - certCache map[string]*tls.Certificate - timeSourceInstance timeSource - logger logging.Logger -} - -func (cs *certStore) timeSource() timeSource { - if cs.timeSourceInstance == nil { - cs.timeSourceInstance = createTimeSource() - } - return cs.timeSourceInstance -} - -func (cs *certStore) initCaCert() (err error) { - if path.FileExists(cs.options.rootCaCert.publicKeyPath) && path.FileExists(cs.options.rootCaCert.privateKeyPath) { - var tlsCert tls.Certificate - if tlsCert, err = tls.LoadX509KeyPair(cs.options.rootCaCert.publicKeyPath, cs.options.rootCaCert.privateKeyPath); err != nil { - return - } else if len(tlsCert.Certificate) > 0 { - cs.caPrivateKey = tlsCert.PrivateKey - cs.caCert, err = x509.ParseCertificate(tlsCert.Certificate[0]) - } - } else { - cs.caCert, cs.caPrivateKey, err = cs.generateCaCert() - } - return -} - -func (cs *certStore) initProvider() { - if cs.keyProvider == nil { - cs.keyProvider = func() (key interface{}, err error) { - return privateKeyForCurve(cs.options) - } - } -} - -func (cs *certStore) generateCaCert() (pubKey *x509.Certificate, privateKey interface{}, err error) { - cs.initProvider() - timeSource := cs.timeSource() - var serialNumber *big.Int - if serialNumber, err = generateSerialNumber(); err != nil { - return - } - - if privateKey, err = cs.keyProvider(); err != nil { - return - } - - template := x509.Certificate{ - SerialNumber: serialNumber, - Subject: pkix.Name{ - Organization: []string{"INetMock"}, - Country: []string{"US"}, - Province: []string{""}, - Locality: []string{"San Francisco"}, - StreetAddress: []string{"Golden Gate Bridge"}, - PostalCode: []string{"94016"}, - }, - IsCA: true, - NotBefore: timeSource.UTCNow().Add(-cs.options.validity.ca.notBeforeRelative), - NotAfter: timeSource.UTCNow().Add(cs.options.validity.ca.notAfterRelative), - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } - - var derBytes []byte - if derBytes, err = x509.CreateCertificate(rand.Reader, &template, &template, publicKey(privateKey), privateKey); err != nil { - return - } - - pubKey, err = x509.ParseCertificate(derBytes) - - if err = writePublicKey(cs.options.rootCaCert.publicKeyPath, derBytes); err != nil { - return - } - - var privateKeyBytes []byte - if privateKeyBytes, err = x509.MarshalPKCS8PrivateKey(privateKey); err != nil { - return - } - - if err = writePrivateKey(cs.options.rootCaCert.privateKeyPath, privateKeyBytes); err != nil { - return - } - - return -} - -func (cs *certStore) getCertificate(serverName string, ip string) (cert *tls.Certificate, err error) { - if cert, ok := cs.certCache[serverName]; ok { - return cert, nil - } - - certPath := filepath.Join(cs.options.certCachePath, fmt.Sprintf("%s.pem", serverName)) - keyPath := filepath.Join(cs.options.certCachePath, fmt.Sprintf("%s.key", serverName)) - - if path.FileExists(certPath) && path.FileExists(keyPath) { - if tlsCert, loadErr := tls.LoadX509KeyPair(certPath, keyPath); loadErr == nil { - cs.certCache[serverName] = &tlsCert - x509Cert, err := x509.ParseCertificate(tlsCert.Certificate[0]) - if err == nil && !certShouldBeRenewed(cs.timeSource(), x509Cert) { - return &tlsCert, nil - } - } - } - - if cert, err = cs.generateDomainCert(serverName, ip); err == nil { - cs.certCache[serverName] = cert - } - - return -} - -func (cs *certStore) generateDomainCert( - serverName string, - localIp string, -) (cert *tls.Certificate, err error) { - cs.initProvider() - - if cs.caCert == nil { - if err = cs.initCaCert(); err != nil { - return - } - } - - var serialNumber *big.Int - if serialNumber, err = generateSerialNumber(); err != nil { - return - } - - var privateKey interface{} - if privateKey, err = cs.keyProvider(); err != nil { - return - } - - notBefore := cs.timeSource().UTCNow().Add(-cs.options.validity.domain.notBeforeRelative) - notAfter := cs.timeSource().UTCNow().Add(cs.options.validity.domain.notAfterRelative) - - cs.logger.Info( - "generate domain certificate", - zap.Time("notBefore", notBefore), - zap.Time("notAfter", notAfter), - ) - - template := x509.Certificate{ - SerialNumber: serialNumber, - Subject: pkix.Name{ - Organization: []string{"INetMock"}, - }, - IPAddresses: []net.IP{net.ParseIP(localIp)}, - DNSNames: []string{serverName}, - NotBefore: notBefore, - NotAfter: notAfter, - KeyUsage: x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - } - - var derBytes []byte - if derBytes, err = x509.CreateCertificate(rand.Reader, &template, cs.caCert, publicKey(privateKey), cs.caPrivateKey); err != nil { - return - } - - if err = writePublicKey(filepath.Join(cs.options.certCachePath, fmt.Sprintf("%s.pem", serverName)), derBytes); err != nil { - return - } - - var privateKeyBytes []byte - if privateKeyBytes, err = x509.MarshalPKCS8PrivateKey(privateKey); err != nil { - return - } - - if cert, err = parseCert(derBytes, privateKeyBytes); err != nil { - return - } - - if err = writePrivateKey(filepath.Join(cs.options.certCachePath, fmt.Sprintf("%s.key", serverName)), privateKeyBytes); err != nil { - return - } - - return -} diff --git a/plugins/tls_interceptor/cert_store_test.go b/plugins/tls_interceptor/cert_store_test.go deleted file mode 100644 index 31ebe6e..0000000 --- a/plugins/tls_interceptor/cert_store_test.go +++ /dev/null @@ -1,213 +0,0 @@ -package main - -import ( - "crypto/tls" - "crypto/x509" - "github.com/baez90/inetmock/pkg/logging" - "go.uber.org/zap" - "io/ioutil" - "os" - "path/filepath" - "reflect" - "testing" - "time" -) - -func Test_generateCaCert(t *testing.T) { - tmpDir, err := ioutil.TempDir(os.TempDir(), "*-inetmock") - if err != nil { - t.Errorf("failed to create temp dir %v", err) - return - } - - options := &tlsOptions{ - ecdsaCurve: "P256", - rootCaCert: cert{ - publicKeyPath: filepath.Join(tmpDir, "localhost.pem"), - privateKeyPath: filepath.Join(tmpDir, "localhost.key"), - }, - validity: validity{ - ca: certValidity{ - notBeforeRelative: time.Hour * 24 * 30, - notAfterRelative: time.Hour * 24 * 30, - }, - }, - } - - certStore := certStore{ - options: options, - } - - defer func() { - _ = os.Remove(tmpDir) - }() - - _, _, err = certStore.generateCaCert() - - if err != nil { - t.Errorf("failed to generate CA cert %v", err) - } - - if _, err = os.Stat(options.rootCaCert.publicKeyPath); err != nil { - t.Errorf("cert file was not created") - } - - if _, err = os.Stat(options.rootCaCert.privateKeyPath); err != nil { - t.Errorf("cert file was not created") - } -} - -func Test_generateDomainCert(t *testing.T) { - - tmpDir, err := ioutil.TempDir(os.TempDir(), "*-inetmock") - if err != nil { - t.Errorf("failed to create temp dir %v", err) - return - } - defer func() { - _ = os.Remove(tmpDir) - }() - - caTlsCert, _ := loadPEMCert(testCaCrt, testCaKey) - caCert, _ := x509.ParseCertificate(caTlsCert.Certificate[0]) - - options := &tlsOptions{ - ecdsaCurve: "P256", - certCachePath: tmpDir, - validity: validity{ - domain: certValidity{ - notAfterRelative: time.Hour * 24 * 30, - notBeforeRelative: time.Hour * 24 * 30, - }, - ca: certValidity{ - notAfterRelative: time.Hour * 24 * 30, - notBeforeRelative: time.Hour * 24 * 30, - }, - }, - } - - zapLogger, _ := zap.NewDevelopment() - logger := logging.NewLogger(zapLogger) - - certStore := certStore{ - options: options, - caCert: caCert, - logger: logger, - caPrivateKey: caTlsCert.PrivateKey, - } - - type args struct { - domain string - ip string - } - tests := []struct { - name string - args args - wantErr bool - }{ - { - name: "Test create google.com cert", - args: args{ - domain: "google.com", - ip: "127.0.0.1", - }, - wantErr: false, - }, - { - name: "Test create golem.de cert", - args: args{ - domain: "golem.de", - ip: "127.0.0.1", - }, - wantErr: false, - }, - { - name: "Test create golem.de cert with any IP address", - args: args{ - domain: "golem.de", - ip: "10.10.0.10", - }, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if domainCert, err := certStore.generateDomainCert( - tt.args.domain, - tt.args.ip, - ); (err != nil) != tt.wantErr || reflect.DeepEqual(domainCert, tls.Certificate{}) { - t.Errorf("generateDomainCert() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func Test_certStore_initCaCert(t *testing.T) { - - tmpDir, err := ioutil.TempDir(os.TempDir(), "*-inetmock") - if err != nil { - t.Errorf("failed to create temp dir %v", err) - return - } - defer func() { - _ = os.Remove(tmpDir) - }() - - caCertPath := filepath.Join(tmpDir, "cacert.pem") - caKeyPath := filepath.Join(tmpDir, "cacert.key") - - if err := ioutil.WriteFile(caCertPath, testCaCrt, 0600); err != nil { - t.Errorf("failed to write cacert.pem %v", err) - return - } - if err := ioutil.WriteFile(caKeyPath, testCaKey, 0600); err != nil { - t.Errorf("failed to write cacert.key %v", err) - return - } - - type fields struct { - options *tlsOptions - caCert *x509.Certificate - } - tests := []struct { - name string - fields fields - wantErr bool - }{ - { - name: "Init CA cert from file", - wantErr: false, - fields: fields{ - options: &tlsOptions{ - rootCaCert: cert{ - publicKeyPath: caCertPath, - privateKeyPath: caKeyPath, - }, - }, - }, - }, - { - name: "Init CA with new cert", - wantErr: false, - fields: fields{ - options: &tlsOptions{ - rootCaCert: cert{ - publicKeyPath: filepath.Join(tmpDir, "nonexistent.pem"), - privateKeyPath: filepath.Join(tmpDir, "nonexistent.key"), - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - cs := &certStore{ - options: tt.fields.options, - caCert: tt.fields.caCert, - } - if err := cs.initCaCert(); (err != nil) != tt.wantErr || cs.caCert == nil { - t.Errorf("initCaCert() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} diff --git a/plugins/tls_interceptor/certs.go b/plugins/tls_interceptor/certs.go deleted file mode 100644 index 17b309e..0000000 --- a/plugins/tls_interceptor/certs.go +++ /dev/null @@ -1,106 +0,0 @@ -package main - -import ( - "crypto/ecdsa" - "crypto/ed25519" - "crypto/elliptic" - "crypto/rand" - "crypto/tls" - "crypto/x509" - "encoding/pem" - "math/big" - "os" -) - -type curveType string - -const ( - certificateBlockType = "CERTIFICATE" - privateKeyBlockType = "PRIVATE KEY" - - curveTypeP224 curveType = "P224" - curveTypeP256 curveType = "P256" - curveTypeP384 curveType = "P384" - curveTypeP521 curveType = "P521" - curveTypeED25519 curveType = "ED25519" -) - -func loadPEMCert(certPEMBytes []byte, keyPEMBytes []byte) (*tls.Certificate, error) { - cert, err := tls.X509KeyPair(certPEMBytes, keyPEMBytes) - return &cert, err -} - -func parseCert(derBytes []byte, privateKeyBytes []byte) (*tls.Certificate, error) { - pemEncodedPublicKey := pem.EncodeToMemory(&pem.Block{Type: certificateBlockType, Bytes: derBytes}) - pemEncodedPrivateKey := pem.EncodeToMemory(&pem.Block{Type: privateKeyBlockType, Bytes: privateKeyBytes}) - cert, err := tls.X509KeyPair(pemEncodedPublicKey, pemEncodedPrivateKey) - return &cert, err -} - -func writePublicKey(crtOutPath string, derBytes []byte) (err error) { - var certOut *os.File - if certOut, err = os.Create(crtOutPath); err != nil { - return - } - if err = pem.Encode(certOut, &pem.Block{Type: certificateBlockType, Bytes: derBytes}); err != nil { - return - } - err = certOut.Close() - return -} - -func writePrivateKey(keyOutPath string, privateKeyBytes []byte) (err error) { - var keyOut *os.File - if keyOut, err = os.OpenFile(keyOutPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600); err != nil { - return - } - - if err = pem.Encode(keyOut, &pem.Block{Type: privateKeyBlockType, Bytes: privateKeyBytes}); err != nil { - return - } - - err = keyOut.Close() - return -} - -func certShouldBeRenewed(timeSource timeSource, cert *x509.Certificate) bool { - lifetime := cert.NotAfter.Sub(cert.NotBefore) - // if the cert is closer to the end of the lifetime than lifetime/2 it should be renewed - if cert.NotAfter.Sub(timeSource.UTCNow()) < lifetime/4 { - return true - } - return false -} - -func generateSerialNumber() (*big.Int, error) { - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) - return rand.Int(rand.Reader, serialNumberLimit) -} - -func privateKeyForCurve(options *tlsOptions) (privateKey interface{}, err error) { - switch options.ecdsaCurve { - case "P224": - privateKey, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader) - case "P256": - privateKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - case "P384": - privateKey, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) - case "P521": - privateKey, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) - default: - _, privateKey, err = ed25519.GenerateKey(rand.Reader) - } - - return -} - -func publicKey(privateKey interface{}) interface{} { - switch k := privateKey.(type) { - case *ecdsa.PrivateKey: - return &k.PublicKey - case ed25519.PrivateKey: - return k.Public().(ed25519.PublicKey) - default: - return nil - } -} diff --git a/plugins/tls_interceptor/certs_test.go b/plugins/tls_interceptor/certs_test.go deleted file mode 100644 index 8d28bdc..0000000 --- a/plugins/tls_interceptor/certs_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package main - -import ( - "crypto/x509" - "testing" - "time" -) - -type testTimeSource struct { - nowValue time.Time -} - -func (t testTimeSource) UTCNow() time.Time { - return t.nowValue -} - -func Test_certShouldBeRenewed(t *testing.T) { - type args struct { - timeSource timeSource - cert *x509.Certificate - } - tests := []struct { - name string - args args - want bool - }{ - { - name: "Detect cert is expired", - want: true, - args: args{ - cert: &x509.Certificate{ - NotAfter: time.Now().UTC().Add(1 * time.Hour), - NotBefore: time.Now().UTC().Add(-1 * time.Hour), - }, - timeSource: testTimeSource{ - nowValue: time.Now().UTC().Add(2 * time.Hour), - }, - }, - }, - { - name: "Detect cert should be renewed", - want: true, - args: args{ - cert: &x509.Certificate{ - NotAfter: time.Now().UTC().Add(1 * time.Hour), - NotBefore: time.Now().UTC().Add(-1 * time.Hour), - }, - timeSource: testTimeSource{ - nowValue: time.Now().UTC().Add(45 * time.Minute), - }, - }, - }, - { - name: "Detect cert shouldn't be renewed", - want: false, - args: args{ - cert: &x509.Certificate{ - NotAfter: time.Now().UTC().Add(1 * time.Hour), - NotBefore: time.Now().UTC().Add(-1 * time.Hour), - }, - timeSource: testTimeSource{ - nowValue: time.Now().UTC().Add(25 * time.Minute), - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := certShouldBeRenewed(tt.args.timeSource, tt.args.cert); got != tt.want { - t.Errorf("certShouldBeRenewed() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/plugins/tls_interceptor/generate_ca_cmd.go b/plugins/tls_interceptor/generate_ca_cmd.go deleted file mode 100644 index fe60313..0000000 --- a/plugins/tls_interceptor/generate_ca_cmd.go +++ /dev/null @@ -1,113 +0,0 @@ -package main - -import ( - "github.com/baez90/inetmock/pkg/logging" - "github.com/spf13/cobra" - "go.uber.org/zap" - "time" -) - -const ( - generateCACertOutPath = "cert-out" - generateCAKeyOutPath = "key-out" - generateCACurveName = "curve" - generateCANotBeforeRelative = "not-before" - generateCANotAfterRelative = "not-after" -) - -func generateCACmd(logger logging.Logger) *cobra.Command { - cmd := &cobra.Command{ - Use: "generate-ca", - Short: "Generate a new CA certificate and corresponding key", - Long: ``, - Run: runGenerateCA(logger), - } - - cmd.Flags().String(generateCACertOutPath, "", "Path where CA cert file should be stored") - cmd.Flags().String(generateCAKeyOutPath, "", "Path where CA key file should be stored") - cmd.Flags().String(generateCACurveName, "", "Name of the curve to use, if empty ED25519 is used, other valid values are [P224, P256,P384,P521]") - cmd.Flags().Duration(generateCANotBeforeRelative, 17520*time.Hour, "Relative time value since when in the past the CA certificate should be valid. The value has a time unit, the greatest time unit is h for hour.") - cmd.Flags().Duration(generateCANotAfterRelative, 17520*time.Hour, "Relative time value until when in the future the CA certificate should be valid. The value has a time unit, the greatest time unit is h for hour.") - - return cmd -} - -func getDurationFlag(cmd *cobra.Command, flagName string, logger logging.Logger) (val time.Duration, err error) { - if val, err = cmd.Flags().GetDuration(flagName); err != nil { - logger.Error( - "failed to parse parse flag", - zap.String("flag", flagName), - zap.Error(err), - ) - } - return -} - -func getStringFlag(cmd *cobra.Command, flagName string, logger logging.Logger) (val string, err error) { - if val, err = cmd.Flags().GetString(flagName); err != nil { - logger.Error( - "failed to parse parse flag", - zap.String("flag", flagName), - zap.Error(err), - ) - } - return -} - -func runGenerateCA(logger logging.Logger) func(cmd *cobra.Command, args []string) { - return func(cmd *cobra.Command, args []string) { - var certOutPath, keyOutPath, curveName string - var notBefore, notAfter time.Duration - var err error - - if certOutPath, err = getStringFlag(cmd, generateCACertOutPath, logger); err != nil { - return - } - - if keyOutPath, err = getStringFlag(cmd, generateCAKeyOutPath, logger); err != nil { - return - } - if curveName, err = getStringFlag(cmd, generateCACurveName, logger); err != nil { - return - } - - if notBefore, err = getDurationFlag(cmd, generateCANotBeforeRelative, logger); err != nil { - return - } - - if notAfter, err = getDurationFlag(cmd, generateCANotAfterRelative, logger); err != nil { - return - } - - logger := logger.With( - zap.String(generateCACurveName, curveName), - zap.String(generateCACertOutPath, certOutPath), - zap.String(generateCAKeyOutPath, keyOutPath), - ) - - certStore := certStore{ - options: &tlsOptions{ - ecdsaCurve: curveType(curveName), - validity: validity{ - ca: certValidity{ - notAfterRelative: notAfter, - notBeforeRelative: notBefore, - }, - }, - rootCaCert: cert{ - publicKeyPath: certOutPath, - privateKeyPath: keyOutPath, - }, - }, - } - - if _, _, err := certStore.generateCaCert(); err != nil { - logger.Error( - "failed to generate CA cert", - zap.Error(err), - ) - } else { - logger.Info("Successfully generated CA cert") - } - } -} diff --git a/plugins/tls_interceptor/go.mod b/plugins/tls_interceptor/go.mod index 9e5b537..646db0a 100644 --- a/plugins/tls_interceptor/go.mod +++ b/plugins/tls_interceptor/go.mod @@ -4,9 +4,8 @@ go 1.14 require ( github.com/baez90/inetmock v0.0.1 - github.com/spf13/cobra v1.0.0 github.com/spf13/viper v1.6.3 - go.uber.org/zap v1.14.1 + go.uber.org/zap v1.15.0 ) replace github.com/baez90/inetmock v0.0.1 => ../../ diff --git a/plugins/tls_interceptor/go.sum b/plugins/tls_interceptor/go.sum index 0495479..e310cb9 100644 --- a/plugins/tls_interceptor/go.sum +++ b/plugins/tls_interceptor/go.sum @@ -147,6 +147,8 @@ go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9E go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -178,6 +180,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa h1:mQTN3ECqfsViCNBgq+A40vdwhkGykrrQlYe3mPj6BoU= golang.org/x/sys v0.0.0-20200409092240-59c9f1ba88fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= diff --git a/plugins/tls_interceptor/init.go b/plugins/tls_interceptor/init.go index a03b56d..e6ca9ab 100644 --- a/plugins/tls_interceptor/init.go +++ b/plugins/tls_interceptor/init.go @@ -19,5 +19,5 @@ func init() { logger: logger, currentConnectionsCount: &sync.WaitGroup{}, } - }, generateCACmd(logger)) + }) } diff --git a/plugins/tls_interceptor/main.go b/plugins/tls_interceptor/main.go index 550d4f0..4bf3b48 100644 --- a/plugins/tls_interceptor/main.go +++ b/plugins/tls_interceptor/main.go @@ -2,9 +2,9 @@ package main import ( "crypto/tls" - "crypto/x509" "fmt" - "github.com/baez90/inetmock/internal/config" + "github.com/baez90/inetmock/pkg/api" + "github.com/baez90/inetmock/pkg/cert" "github.com/baez90/inetmock/pkg/logging" "go.uber.org/zap" "net" @@ -17,16 +17,16 @@ const ( ) type tlsInterceptor struct { + options tlsOptions logger logging.Logger listener net.Listener - certStore *certStore - options *tlsOptions + certStore cert.Store shutdownRequested bool currentConnectionsCount *sync.WaitGroup currentConnections []*proxyConn } -func (t *tlsInterceptor) Start(config config.HandlerConfig) (err error) { +func (t *tlsInterceptor) Start(config api.HandlerConfig) (err error) { t.options = loadFromConfig(config.Options()) addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) @@ -35,33 +35,7 @@ func (t *tlsInterceptor) Start(config config.HandlerConfig) (err error) { zap.String("target", t.options.redirectionTarget.address()), ) - t.certStore = &certStore{ - options: t.options, - certCache: make(map[string]*tls.Certificate), - logger: t.logger, - } - - if err = t.certStore.initCaCert(); err != nil { - t.logger.Error( - "failed to initialize CA cert", - zap.Error(err), - ) - err = fmt.Errorf( - "failed to initialize CA cert: %w", - err, - ) - return - } - - rootCaPool := x509.NewCertPool() - rootCaPool.AddCert(t.certStore.caCert) - - tlsConfig := &tls.Config{ - GetCertificate: t.getCert, - RootCAs: rootCaPool, - } - - if t.listener, err = tls.Listen("tcp", addr, tlsConfig); err != nil { + if t.listener, err = tls.Listen("tcp", addr, api.ServicesInstance().CertStore().TLSConfig()); err != nil { t.logger.Fatal( "failed to create tls listener", zap.Error(err), @@ -122,23 +96,6 @@ func (t *tlsInterceptor) startListener() { } } -func (t *tlsInterceptor) getCert(info *tls.ClientHelloInfo) (cert *tls.Certificate, err error) { - var localIp string - if localIp, err = extractIPFromAddress(info.Conn.LocalAddr().String()); err != nil { - localIp = "127.0.0.1" - } - if cert, err = t.certStore.getCertificate(info.ServerName, localIp); err != nil { - t.logger.Error( - "error while resolving certificate", - zap.String("serverName", info.ServerName), - zap.String("localAddr", localIp), - zap.Error(err), - ) - } - - return -} - func (t *tlsInterceptor) proxyConn(conn net.Conn) { defer conn.Close() diff --git a/plugins/tls_interceptor/protocol_options.go b/plugins/tls_interceptor/protocol_options.go index c13eedf..47ae1f0 100644 --- a/plugins/tls_interceptor/protocol_options.go +++ b/plugins/tls_interceptor/protocol_options.go @@ -3,37 +3,13 @@ package main import ( "fmt" "github.com/spf13/viper" - "time" ) const ( - certCachePathConfigKey = "certCachePath" - ecdsaCurveConfigKey = "ecdsaCurve" - targetIpAddressConfigKey = "target.ipAddress" - targetPortConfigKey = "target.port" - publicKeyConfigKey = "rootCaCert.publicKey" - privateKeyPathConfigKey = "rootCaCert.privateKey" - caCertValidityNotBeforeKey = "validity.ca.notBeforeRelative" - caCertValidityNotAfterKey = "validity.ca.notAfterRelative" - domainCertValidityNotBeforeKey = "validity.domain.notBeforeRelative" - domainCertValidityNotAfterKey = "validity.domain.notAfterRelative" + targetIpAddressConfigKey = "target.ipAddress" + targetPortConfigKey = "target.port" ) -type cert struct { - publicKeyPath string - privateKeyPath string -} - -type certValidity struct { - notBeforeRelative time.Duration - notAfterRelative time.Duration -} - -type validity struct { - ca certValidity - domain certValidity -} - type redirectionTarget struct { ipAddress string port uint16 @@ -44,35 +20,14 @@ func (rt redirectionTarget) address() string { } type tlsOptions struct { - rootCaCert cert - certCachePath string redirectionTarget redirectionTarget - ecdsaCurve curveType - validity validity } -func loadFromConfig(config *viper.Viper) *tlsOptions { - - return &tlsOptions{ - certCachePath: config.GetString(certCachePathConfigKey), - ecdsaCurve: curveType(config.GetString(ecdsaCurveConfigKey)), +func loadFromConfig(config *viper.Viper) tlsOptions { + return tlsOptions{ redirectionTarget: redirectionTarget{ ipAddress: config.GetString(targetIpAddressConfigKey), port: uint16(config.GetInt(targetPortConfigKey)), }, - validity: validity{ - ca: certValidity{ - notBeforeRelative: config.GetDuration(caCertValidityNotBeforeKey), - notAfterRelative: config.GetDuration(caCertValidityNotAfterKey), - }, - domain: certValidity{ - notBeforeRelative: config.GetDuration(domainCertValidityNotBeforeKey), - notAfterRelative: config.GetDuration(domainCertValidityNotAfterKey), - }, - }, - rootCaCert: cert{ - publicKeyPath: config.GetString(publicKeyConfigKey), - privateKeyPath: config.GetString(privateKeyPathConfigKey), - }, } } diff --git a/plugins/tls_interceptor/test_setup.go b/plugins/tls_interceptor/test_setup.go deleted file mode 100644 index bc90685..0000000 --- a/plugins/tls_interceptor/test_setup.go +++ /dev/null @@ -1,55 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "time" -) - -var ( - testCaCrt []byte - testCaKey []byte -) - -func init() { - tmpDir, err := ioutil.TempDir(os.TempDir(), "*-inetmock") - if err != nil { - panic(fmt.Sprintf("failed to create temp dir %v", err)) - } - - options := &tlsOptions{ - ecdsaCurve: "P256", - rootCaCert: cert{ - publicKeyPath: filepath.Join(tmpDir, "localhost.pem"), - privateKeyPath: filepath.Join(tmpDir, "localhost.key"), - }, - validity: validity{ - ca: certValidity{ - notBeforeRelative: time.Hour * 24 * 30, - notAfterRelative: time.Hour * 24 * 30, - }, - }, - } - - certStore := certStore{ - options: options, - keyProvider: func() (key interface{}, err error) { - return privateKeyForCurve(options) - }, - } - - defer func() { - _ = os.Remove(tmpDir) - }() - - _, _, err = certStore.generateCaCert() - - testCaCrt, _ = ioutil.ReadFile(options.rootCaCert.publicKeyPath) - testCaKey, _ = ioutil.ReadFile(options.rootCaCert.privateKeyPath) - - if err != nil { - panic(fmt.Sprintf("failed to generate CA cert %v", err)) - } -} diff --git a/plugins/tls_interceptor/time_source.go b/plugins/tls_interceptor/time_source.go deleted file mode 100644 index ed7c7ff..0000000 --- a/plugins/tls_interceptor/time_source.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import "time" - -type timeSource interface { - UTCNow() time.Time -} - -func createTimeSource() timeSource { - return &defaultTimeSource{} -} - -type defaultTimeSource struct { -} - -func (d defaultTimeSource) UTCNow() time.Time { - return time.Now().UTC() -} From a67b8ed36d2b67b6fc658f2a2074b715980d14d4 Mon Sep 17 00:00:00 2001 From: Peter Kurfer Date: Sun, 26 Apr 2020 01:18:35 +0200 Subject: [PATCH 9/9] Improve TLS connection tracking to avoid memory or connection leaks --- plugins/tls_interceptor/go.mod | 1 + plugins/tls_interceptor/go.sum | 2 ++ plugins/tls_interceptor/init.go | 2 ++ plugins/tls_interceptor/main.go | 12 ++++++++---- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/plugins/tls_interceptor/go.mod b/plugins/tls_interceptor/go.mod index 646db0a..ace8acb 100644 --- a/plugins/tls_interceptor/go.mod +++ b/plugins/tls_interceptor/go.mod @@ -4,6 +4,7 @@ go 1.14 require ( github.com/baez90/inetmock v0.0.1 + github.com/google/uuid v1.1.1 github.com/spf13/viper v1.6.3 go.uber.org/zap v1.15.0 ) diff --git a/plugins/tls_interceptor/go.sum b/plugins/tls_interceptor/go.sum index e310cb9..4b660b7 100644 --- a/plugins/tls_interceptor/go.sum +++ b/plugins/tls_interceptor/go.sum @@ -41,6 +41,8 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= diff --git a/plugins/tls_interceptor/init.go b/plugins/tls_interceptor/init.go index e6ca9ab..2553df0 100644 --- a/plugins/tls_interceptor/init.go +++ b/plugins/tls_interceptor/init.go @@ -4,6 +4,7 @@ import ( "github.com/baez90/inetmock/internal/plugins" "github.com/baez90/inetmock/pkg/api" "github.com/baez90/inetmock/pkg/logging" + "github.com/google/uuid" "go.uber.org/zap" "sync" ) @@ -18,6 +19,7 @@ func init() { return &tlsInterceptor{ logger: logger, currentConnectionsCount: &sync.WaitGroup{}, + currentConnections: make(map[uuid.UUID]*proxyConn), } }) } diff --git a/plugins/tls_interceptor/main.go b/plugins/tls_interceptor/main.go index 4bf3b48..6cb8ce2 100644 --- a/plugins/tls_interceptor/main.go +++ b/plugins/tls_interceptor/main.go @@ -6,6 +6,7 @@ import ( "github.com/baez90/inetmock/pkg/api" "github.com/baez90/inetmock/pkg/cert" "github.com/baez90/inetmock/pkg/logging" + "github.com/google/uuid" "go.uber.org/zap" "net" "sync" @@ -23,7 +24,7 @@ type tlsInterceptor struct { certStore cert.Store shutdownRequested bool currentConnectionsCount *sync.WaitGroup - currentConnections []*proxyConn + currentConnections map[uuid.UUID]*proxyConn } func (t *tlsInterceptor) Start(config api.HandlerConfig) (err error) { @@ -98,6 +99,7 @@ func (t *tlsInterceptor) startListener() { func (t *tlsInterceptor) proxyConn(conn net.Conn) { defer conn.Close() + defer t.currentConnectionsCount.Done() rAddr, err := net.ResolveTCPAddr("tcp", t.options.redirectionTarget.address()) if err != nil { @@ -117,14 +119,16 @@ func (t *tlsInterceptor) proxyConn(conn net.Conn) { } defer targetConn.Close() - t.currentConnections = append(t.currentConnections, &proxyConn{ + proxyCon := &proxyConn{ source: conn, target: targetConn, - }) + } + conUID := uuid.New() + t.currentConnections[conUID] = proxyCon Pipe(conn, targetConn) + delete(t.currentConnections, conUID) - t.currentConnectionsCount.Done() t.logger.Info( "connection closed", zap.String("remoteAddr", conn.RemoteAddr().String()),