Add basic DNS and DNS-over-TLS implementation

- add random and incremental DNS fallback strategy
- add option to handle DNS requests based on regex patterns
- made Makefiles plugin independent
- extended config
- set default plugins directory in Dockerfile
This commit is contained in:
Peter 2020-04-02 00:58:44 +02:00
parent 0ed90708d8
commit 63ba6da810
Signed by: prskr
GPG key ID: C1DB5D2E8DB512F9
15 changed files with 546 additions and 27 deletions

View file

@ -32,6 +32,8 @@ RUN make CONTAINER=yes
FROM scratch FROM scratch
ENV INETMOCK_PLUGINS_DIRECTORY=/app/plugins/
WORKDIR /app WORKDIR /app
COPY --from=build /etc/passwd /etc/group /etc/ COPY --from=build /etc/passwd /etc/group /etc/

View file

@ -38,4 +38,38 @@ endpoints:
certCachePath: /tmp/inetmock/ certCachePath: /tmp/inetmock/
target: target:
ipAddress: 127.0.0.1 ipAddress: 127.0.0.1
port: 80 port: 80
plainDns:
handler: dns_mock
listenAddress: 0.0.0.0
port: 53
options:
fallback:
strategy: incremental
args:
startIP: 10.0.0.0
rules:
- pattern: ".*\\.google\\.com"
response: 1.1.1.1
- pattern: ".*\\.reddit\\.com"
response: 2.2.2.2
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

2
go.mod
View file

@ -3,10 +3,10 @@ module github.com/baez90/inetmock
go 1.13 go 1.13
require ( require (
github.com/miekg/dns v1.1.29
github.com/spf13/cobra v0.0.6 github.com/spf13/cobra v0.0.6
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.4.0 github.com/spf13/viper v1.4.0
go.uber.org/zap v1.14.1 go.uber.org/zap v1.14.1
golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect gopkg.in/yaml.v2 v2.2.8 // indirect
) )

15
go.sum
View file

@ -60,6 +60,8 @@ 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 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 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/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 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
@ -129,11 +131,14 @@ 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-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 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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-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-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 h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 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.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-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-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-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -141,10 +146,13 @@ 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-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-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-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/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-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-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-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/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-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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -154,6 +162,8 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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 h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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/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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -164,9 +174,10 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 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 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-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f h1:3MlESg/jvTr87F4ttA/q4B+uhe/q6qleC9/DP+IwQmY= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA=
golang.org/x/tools v0.0.0-20191127201027-ecd32218bd7f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 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-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/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/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.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=

View file

@ -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_NAMEs) $(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

View file

@ -0,0 +1,75 @@
package main
import (
"encoding/binary"
"github.com/spf13/viper"
"math"
"math/rand"
"net"
"unsafe"
)
const (
randomIPStrategyName = "random"
incrementalIPStrategyName = "incremental"
startIPConfigKey = "startIP"
)
var (
fallbackStrategies map[string]ResolverFactory
)
type ResolverFactory func(conf *viper.Viper) ResolverFallback
func init() {
fallbackStrategies = make(map[string]ResolverFactory)
fallbackStrategies[incrementalIPStrategyName] = func(conf *viper.Viper) ResolverFallback {
return &incrementalIPFallback{
latestIp: ipToInt32(net.ParseIP(conf.GetString(startIPConfigKey))),
}
}
fallbackStrategies[randomIPStrategyName] = func(conf *viper.Viper) ResolverFallback {
return &randomIPFallback{}
}
}
func CreateResolverFallback(name string, config *viper.Viper) ResolverFallback {
if factory, ok := fallbackStrategies[name]; ok {
return factory(config)
} else {
return fallbackStrategies[randomIPStrategyName](config)
}
}
type ResolverFallback interface {
GetIP() net.IP
}
type incrementalIPFallback struct {
latestIp uint32
}
func (i *incrementalIPFallback) GetIP() net.IP {
if i.latestIp < math.MaxInt32 {
i.latestIp += 1
}
return uint32ToIP(i.latestIp)
}
type randomIPFallback struct {
}
func (randomIPFallback) GetIP() net.IP {
return uint32ToIP(uint32(rand.Int31()))
}
func uint32ToIP(i uint32) net.IP {
bytes := (*[4]byte)(unsafe.Pointer(&i))[:]
return net.IPv4(bytes[3], bytes[2], bytes[1], bytes[0])
}
func ipToInt32(ip net.IP) uint32 {
v4 := ip.To4()
result := binary.BigEndian.Uint32(v4)
return result
}

View file

@ -0,0 +1,106 @@
package main
import (
"net"
"reflect"
"testing"
)
func Test_randomIPFallback_GetIP(t *testing.T) {
ra := randomIPFallback{}
for i := 0; i < 1000; i++ {
if got := ra.GetIP(); reflect.DeepEqual(got, net.IP{}) {
t.Errorf("GetIP() = %v", got)
}
}
}
func Test_incrementalIPFallback_GetIP(t *testing.T) {
type fields struct {
latestIp uint32
}
tests := []struct {
name string
fields fields
want []net.IP
}{
{
name: "Expect the next icremental IP",
fields: fields{
latestIp: 167772160,
},
want: []net.IP{
net.IPv4(10, 0, 0, 1),
},
},
{
name: "Expect a sequence of 5",
fields: fields{
latestIp: 167772160,
},
want: []net.IP{
net.IPv4(10, 0, 0, 1),
net.IPv4(10, 0, 0, 2),
net.IPv4(10, 0, 0, 3),
net.IPv4(10, 0, 0, 4),
net.IPv4(10, 0, 0, 5),
},
},
{
name: "Expect next block to be incremented",
fields: fields{
latestIp: 167772413,
},
want: []net.IP{
net.IPv4(10, 0, 0, 254),
net.IPv4(10, 0, 0, 255),
net.IPv4(10, 0, 1, 0),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
i := &incrementalIPFallback{
latestIp: tt.fields.latestIp,
}
for k := 0; k < len(tt.want); k++ {
if got := i.GetIP(); !reflect.DeepEqual(got, tt.want[k]) {
t.Errorf("GetIP() = %v, want %v", got, tt.want[k])
}
}
})
}
}
func Test_ipToInt32(t *testing.T) {
type args struct {
ip net.IP
}
tests := []struct {
name string
args args
want uint32
}{
{
name: "Convert 188.193.106.113 to int",
args: args{
ip: net.ParseIP("188.193.106.113"),
},
want: 3166792305,
},
{
name: "Convert 192.168.178.10 to int",
args: args{
ip: net.ParseIP("192.168.178.10"),
},
want: 3232281098,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ipToInt32(tt.args.ip); got != tt.want {
t.Errorf("ipToInt32() = %v, want %v", got, tt.want)
}
})
}
}

View file

@ -0,0 +1,25 @@
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"
)
const (
name = "dns_mock"
)
func init() {
logger, _ := logging.CreateLogger()
logger = logger.With(
zap.String("ProtocolHandler", name),
)
plugins.Registry().RegisterHandler(name, func() api.ProtocolHandler {
return &dnsHandler{
logger: logger,
}
})
}

View file

@ -0,0 +1,75 @@
package main
import (
"fmt"
"github.com/baez90/inetmock/internal/config"
"github.com/miekg/dns"
"go.uber.org/zap"
"sync"
)
type dnsHandler struct {
logger *zap.Logger
dnsServer []*dns.Server
}
func (d *dnsHandler) Run(config config.HandlerConfig) {
options := loadFromConfig(config.Options())
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
handler := &regexHandler{
fallback: options.Fallback,
logger: d.logger,
}
for _, rule := range options.Rules {
d.logger.Info(
"register DNS rule",
zap.String("pattern", rule.pattern.String()),
zap.String("response", rule.response.String()),
)
handler.AddRule(rule)
}
d.logger = d.logger.With(
zap.String("address", addr),
)
d.dnsServer = []*dns.Server{
{
Addr: addr,
Net: "udp",
Handler: handler,
},
{
Addr: addr,
Net: "tcp",
Handler: handler,
},
}
for _, dnsServer := range d.dnsServer {
go d.startServer(dnsServer)
}
}
func (d *dnsHandler) startServer(dnsServer *dns.Server) {
if err := dnsServer.ListenAndServe(); err != nil {
d.logger.Error(
"failed to start DNS server listener",
zap.Error(err),
)
}
}
func (d *dnsHandler) Shutdown(wg *sync.WaitGroup) {
for _, dnsServer := range d.dnsServer {
if err := dnsServer.Shutdown(); err != nil {
d.logger.Error(
"failed to shutdown server",
zap.Error(err),
)
}
}
wg.Done()
}

View file

@ -0,0 +1,56 @@
package main
import (
"github.com/spf13/viper"
"net"
"regexp"
)
const (
rulesConfigKey = "rules"
patternConfigKey = "pattern"
responseConfigKey = "response"
fallbackStrategyConfigKey = "fallback.strategy"
fallbackArgsConfigKey = "fallback.args"
)
type resolverRule struct {
pattern *regexp.Regexp
response net.IP
}
type dnsOptions struct {
Rules []resolverRule
Fallback ResolverFallback
}
func loadFromConfig(config *viper.Viper) dnsOptions {
options := dnsOptions{}
anonRules := config.Get(rulesConfigKey).([]interface{})
for _, rule := range anonRules {
innerData := rule.(map[interface{}]interface{})
var err error
var compiledPattern *regexp.Regexp
var response net.IP
if compiledPattern, err = regexp.Compile(innerData[patternConfigKey].(string)); err != nil {
continue
}
if response = net.ParseIP(innerData[responseConfigKey].(string)); response == nil {
continue
}
options.Rules = append(options.Rules, resolverRule{
pattern: compiledPattern,
response: response,
})
}
options.Fallback = CreateResolverFallback(
config.GetString(fallbackStrategyConfigKey),
config.Sub(fallbackArgsConfigKey),
)
return options
}

View file

@ -0,0 +1,86 @@
package main
import (
"github.com/miekg/dns"
"go.uber.org/zap"
)
type regexHandler struct {
routes []resolverRule
fallback ResolverFallback
logger *zap.Logger
}
func (r2 *regexHandler) AddRule(rule resolverRule) {
r2.routes = append(r2.routes, rule)
}
func (r2 regexHandler) ServeDNS(w dns.ResponseWriter, r *dns.Msg) {
m := new(dns.Msg)
m.Compress = false
m.SetReply(r)
switch r.Opcode {
case dns.OpcodeQuery:
r2.handleQuery(m)
}
if err := w.WriteMsg(m); err != nil {
r2.logger.Error(
"Failed to write DNS response message",
zap.Error(err),
)
}
}
func (r2 regexHandler) handleQuery(m *dns.Msg) {
for _, q := range m.Question {
r2.logger.Info(
"handling question",
zap.String("question", q.Name),
)
switch q.Qtype {
case dns.TypeA:
for _, rule := range r2.routes {
if rule.pattern.MatchString(q.Name) {
m.Authoritative = true
answer := &dns.A{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeA,
Class: dns.ClassINET,
Ttl: 60,
},
A: rule.response,
}
m.Answer = append(m.Answer, answer)
r2.logger.Info(
"matched DNS rule",
zap.String("pattern", rule.pattern.String()),
zap.String("response", rule.response.String()),
)
return
}
}
r2.handleFallbackForMessage(m, q)
}
}
}
func (r2 regexHandler) handleFallbackForMessage(m *dns.Msg, q dns.Question) {
fallbackIP := r2.fallback.GetIP()
answer := &dns.A{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeA,
Class: dns.ClassINET,
Ttl: 60,
},
A: fallbackIP,
}
r2.logger.Info(
"Falling back to generated IP",
zap.String("response", fallbackIP.String()),
)
m.Authoritative = true
m.Answer = append(m.Answer, answer)
}

View file

@ -6,7 +6,7 @@ GOARGS = GOOS=linux GOARCH=amd64
GO_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" GO_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s"
GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo
GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l" GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l"
PLUGIN_NAME = http_mock.so PLUGIN_NAME = $(shell basename $(DIR)).so
OUT_DIR = $(DIR)../../../plugins OUT_DIR = $(DIR)../../../plugins
DEBUG_PORT = 2345 DEBUG_PORT = 2345

View file

@ -0,0 +1,21 @@
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"
)
func init() {
logger, _ := logging.CreateLogger()
logger = logger.With(
zap.String("ProtocolHandler", name),
)
plugins.Registry().RegisterHandler(name, func() api.ProtocolHandler {
return &httpHandler{
logger: logger,
router: &RegexpHandler{},
}
})
}

View file

@ -4,9 +4,6 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/baez90/inetmock/internal/config" "github.com/baez90/inetmock/internal/config"
"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/baez90/inetmock/pkg/path"
"go.uber.org/zap" "go.uber.org/zap"
"net/http" "net/http"
@ -19,13 +16,13 @@ const (
name = "http_mock" name = "http_mock"
) )
type httpPlugin struct { type httpHandler struct {
logger *zap.Logger logger *zap.Logger
router *RegexpHandler router *RegexpHandler
server *http.Server server *http.Server
} }
func (p *httpPlugin) Run(config config.HandlerConfig) { func (p *httpHandler) Run(config config.HandlerConfig) {
options := loadFromConfig(config.Options()) options := loadFromConfig(config.Options())
addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port()) addr := fmt.Sprintf("%s:%d", config.ListenAddress(), config.Port())
p.server = &http.Server{Addr: addr, Handler: p.router} p.server = &http.Server{Addr: addr, Handler: p.router}
@ -40,7 +37,7 @@ func (p *httpPlugin) Run(config config.HandlerConfig) {
go p.startServer() go p.startServer()
} }
func (p *httpPlugin) Shutdown(wg *sync.WaitGroup) { func (p *httpHandler) Shutdown(wg *sync.WaitGroup) {
if err := p.server.Close(); err != nil { if err := p.server.Close(); err != nil {
p.logger.Error( p.logger.Error(
"failed to shutdown HTTP server", "failed to shutdown HTTP server",
@ -51,7 +48,7 @@ func (p *httpPlugin) Shutdown(wg *sync.WaitGroup) {
wg.Done() wg.Done()
} }
func (p *httpPlugin) startServer() { func (p *httpHandler) startServer() {
if err := p.server.ListenAndServe(); err != nil { if err := p.server.ListenAndServe(); err != nil {
p.logger.Error( p.logger.Error(
"failed to start http listener", "failed to start http listener",
@ -60,7 +57,7 @@ func (p *httpPlugin) startServer() {
} }
} }
func (p *httpPlugin) setupRoute(rule targetRule) { func (p *httpHandler) setupRoute(rule targetRule) {
var compiled *regexp.Regexp var compiled *regexp.Regexp
var err error var err error
if compiled, err = regexp.Compile(rule.pattern); err != nil { if compiled, err = regexp.Compile(rule.pattern); err != nil {
@ -101,16 +98,3 @@ func createHandlerForTarget(logger *zap.Logger, targetPath string) http.Handler
http.ServeFile(writer, request, targetFilePath) http.ServeFile(writer, request, targetFilePath)
}) })
} }
func init() {
logger, _ := logging.CreateLogger()
logger = logger.With(
zap.String("ProtocolHandler", name),
)
plugins.Registry().RegisterHandler(name, func() api.ProtocolHandler {
return &httpPlugin{
logger: logger,
router: &RegexpHandler{},
}
})
}

View file

@ -6,7 +6,7 @@ GOARGS = GOOS=linux GOARCH=amd64
GO_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" GO_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s"
GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo GO_CONTAINER_BUILD_ARGS = -buildmode=plugin -ldflags="-w -s" -a -installsuffix cgo
GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l" GO_DEBUG_BUILD_ARGS = -buildmode=plugin -gcflags "all=-N -l"
PLUGIN_NAME = tls_interceptor.so PLUGIN_NAME = $(shell basename $(DIR)).so
OUT_DIR = $(DIR)../../../plugins OUT_DIR = $(DIR)../../../plugins
DEBUG_PORT = 2345 DEBUG_PORT = 2345