mirror of https://github.com/0xERR0R/blocky.git
Merge pull request #19 from 0xERR0R/development
[pull] development from 0xERR0R:development
This commit is contained in:
commit
0850346569
|
@ -11,30 +11,36 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.CR_PAT }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Extract branch name
|
||||
shell: bash
|
||||
run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})"
|
||||
id: extract_branch
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
|
||||
|
@ -42,6 +48,9 @@ jobs:
|
|||
tags: |
|
||||
ghcr.io/0xerr0r/blocky:${{ steps.extract_branch.outputs.branch }}
|
||||
spx01/blocky:${{ steps.extract_branch.outputs.branch }}
|
||||
cache-from: type=registry,ref=ghcr.io/0xerr0r/blocky:buildcache
|
||||
cache-to: type=registry,ref=ghcr.io/0xerr0r/blocky:buildcache,mode=max
|
||||
|
||||
- name: Scan image
|
||||
uses: anchore/scan-action@v3
|
||||
id: scan
|
||||
|
@ -49,6 +58,7 @@ jobs:
|
|||
image: "spx01/blocky:${{ steps.extract_branch.outputs.branch }}"
|
||||
fail-build: false
|
||||
acs-report-enable: true
|
||||
|
||||
- name: upload Anchore scan SARIF report
|
||||
uses: github/codeql-action/upload-sarif@v1
|
||||
with:
|
||||
|
|
|
@ -35,32 +35,34 @@ jobs:
|
|||
images: spx01/blocky,ghcr.io/0xerr0r/blocky
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.CR_PAT }}
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||
cache-from: type=registry,ref=ghcr.io/0xerr0r/blocky:buildcache
|
||||
cache-to: type=registry,ref=ghcr.io/0xerr0r/blocky:buildcache,mode=max
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
|
|
40
Dockerfile
40
Dockerfile
|
@ -1,12 +1,19 @@
|
|||
# build stage
|
||||
FROM golang:1-alpine AS build-env
|
||||
RUN apk add --no-cache \
|
||||
build-base \
|
||||
linux-headers \
|
||||
coreutils \
|
||||
binutils \
|
||||
libtool \
|
||||
musl-dev \
|
||||
git \
|
||||
make \
|
||||
gcc \
|
||||
libc-dev \
|
||||
zip \
|
||||
ca-certificates
|
||||
ca-certificates \
|
||||
libcap
|
||||
|
||||
ENV GO111MODULE=on \
|
||||
CGO_ENABLED=0
|
||||
|
@ -20,24 +27,35 @@ RUN go mod download
|
|||
ADD . .
|
||||
|
||||
ARG opts
|
||||
RUN env ${opts} make build
|
||||
RUN env ${opts} make build-static
|
||||
RUN setcap 'cap_net_bind_service=+ep' /src/bin/blocky
|
||||
|
||||
RUN adduser -S -D -H -h /app -s /sbin/nologin blocky
|
||||
RUN chown blocky /src/bin/blocky
|
||||
RUN tail -n 1 /etc/passwd > /tmp/blocky_passwd
|
||||
|
||||
# get all required files and build a root directory
|
||||
FROM scratch AS combine-env
|
||||
|
||||
COPY --from=build-env /src/bin/blocky /app/blocky
|
||||
COPY --from=build-env /tmp/blocky_passwd /etc/passwd
|
||||
COPY --from=build-env /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
|
||||
|
||||
# final stage
|
||||
FROM alpine:3.16
|
||||
FROM scratch
|
||||
|
||||
LABEL org.opencontainers.image.source="https://github.com/0xERR0R/blocky" \
|
||||
org.opencontainers.image.url="https://github.com/0xERR0R/blocky" \
|
||||
org.opencontainers.image.title="DNS proxy as ad-blocker for local network"
|
||||
|
||||
COPY --from=build-env /src/bin/blocky /app/blocky
|
||||
RUN apk add --no-cache ca-certificates bind-tools tini tzdata libcap && \
|
||||
adduser -S -D -H -h /app -s /sbin/nologin blocky && \
|
||||
setcap 'cap_net_bind_service=+ep' /app/blocky
|
||||
|
||||
HEALTHCHECK --interval=1m --timeout=3s CMD dig @127.0.0.1 -p 53 healthcheck.blocky +tcp +short || exit 1
|
||||
COPY --from=combine-env / /
|
||||
|
||||
USER blocky
|
||||
WORKDIR /app
|
||||
|
||||
ENTRYPOINT ["/sbin/tini", "--"]
|
||||
CMD ["sh", "-c", "/app/blocky --config ${CONFIG_FILE:-/app/config.yml}"]
|
||||
ENV BLOCKY_CONFIG_FILE=/app/config.yml
|
||||
|
||||
ENTRYPOINT ["/app/blocky"]
|
||||
|
||||
HEALTHCHECK --interval=1m --timeout=3s CMD ["/app/blocky", "healthcheck"]
|
||||
|
|
8
Makefile
8
Makefile
|
@ -5,7 +5,7 @@
|
|||
|
||||
VERSION := $(shell git describe --always --tags)
|
||||
BUILD_TIME=$(shell date '+%Y%m%d-%H%M%S')
|
||||
DOCKER_IMAGE_NAME="spx01/blocky"
|
||||
DOCKER_IMAGE_NAME=spx01/blocky
|
||||
BINARY_NAME=blocky
|
||||
BIN_OUT_DIR=bin
|
||||
|
||||
|
@ -29,6 +29,10 @@ build: ## Build binary
|
|||
go generate ./...
|
||||
go build -v -ldflags="-w -s -X github.com/0xERR0R/blocky/util.Version=${VERSION} -X github.com/0xERR0R/blocky/util.BuildTime=${BUILD_TIME}" -o $(BIN_OUT_DIR)/$(BINARY_NAME)$(BINARY_SUFFIX)
|
||||
|
||||
build-static: ## Build static binary
|
||||
go generate ./...
|
||||
go build -tags static -v -ldflags="-linkmode external -extldflags -static -X github.com/0xERR0R/blocky/util.Version=${VERSION} -X github.com/0xERR0R/blocky/util.BuildTime=${BUILD_TIME}" -o $(BIN_OUT_DIR)/$(BINARY_NAME)$(BINARY_SUFFIX)
|
||||
|
||||
test: ## run tests
|
||||
go run github.com/onsi/ginkgo/v2/ginkgo -v --coverprofile=coverage.txt --covermode=atomic -cover ./...
|
||||
|
||||
|
@ -45,7 +49,7 @@ fmt: ## gofmt and goimports all go files
|
|||
find . -name '*.go' | while read -r file; do gofmt -w -s "$$file"; goimports -w "$$file"; done
|
||||
|
||||
docker-build: ## Build docker image
|
||||
docker build --network=host --tag ${DOCKER_IMAGE_NAME} .
|
||||
docker buildx build -o type=docker --network=host -t ${DOCKER_IMAGE_NAME} .
|
||||
|
||||
help: ## Shows help
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultDNSPort = 53
|
||||
)
|
||||
|
||||
func NewHealthcheckCommand() *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "healthcheck",
|
||||
Short: "performs healthcheck",
|
||||
RunE: healthcheck,
|
||||
}
|
||||
|
||||
c.Flags().Uint16P("port", "p", defaultDNSPort, "healthcheck port 5333")
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func healthcheck(cmd *cobra.Command, args []string) error {
|
||||
port, _ := cmd.Flags().GetUint16("port")
|
||||
|
||||
c := new(dns.Client)
|
||||
c.Net = "tcp"
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion("healthcheck.blocky.", dns.TypeA)
|
||||
|
||||
_, _, err := c.Exchange(m, net.JoinHostPort("127.0.0.1", fmt.Sprintf("%d", port)))
|
||||
|
||||
if err == nil {
|
||||
fmt.Println("OK")
|
||||
} else {
|
||||
fmt.Println("NOT OK")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Healthcheck command", func() {
|
||||
Describe("Call healthcheck command", func() {
|
||||
It("should fail", func() {
|
||||
c := NewHealthcheckCommand()
|
||||
c.SetArgs([]string{"-p", "5344"})
|
||||
|
||||
err := c.Execute()
|
||||
|
||||
Expect(err).Should(HaveOccurred())
|
||||
})
|
||||
|
||||
It("shoul succeed", func() {
|
||||
srv := createMockServer()
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
err := srv.ListenAndServe()
|
||||
Expect(err).Should(Succeed())
|
||||
}()
|
||||
DeferCleanup(srv.Shutdown)
|
||||
|
||||
Eventually(func() error {
|
||||
c := NewHealthcheckCommand()
|
||||
c.SetArgs([]string{"-p", "5333"})
|
||||
|
||||
return c.Execute()
|
||||
}, "1s").Should(Succeed())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func createMockServer() *dns.Server {
|
||||
res := &dns.Server{
|
||||
Addr: "127.0.0.1:5333",
|
||||
Net: "tcp",
|
||||
Handler: dns.NewServeMux(),
|
||||
NotifyStartedFunc: func() {
|
||||
fmt.Println("Mock helthcheck server is up")
|
||||
},
|
||||
}
|
||||
|
||||
th := res.Handler.(*dns.ServeMux)
|
||||
th.HandleFunc("healthcheck.blocky", func(w dns.ResponseWriter, request *dns.Msg) {
|
||||
resp := new(dns.Msg)
|
||||
resp.SetReply(request)
|
||||
resp.Rcode = dns.RcodeSuccess
|
||||
|
||||
err := w.WriteMsg(resp)
|
||||
Expect(err).Should(Succeed())
|
||||
})
|
||||
|
||||
return res
|
||||
}
|
23
cmd/root.go
23
cmd/root.go
|
@ -20,9 +20,11 @@ var (
|
|||
)
|
||||
|
||||
const (
|
||||
defaultPort = 4000
|
||||
defaultHost = "localhost"
|
||||
defaultConfigPath = "./config.yml"
|
||||
defaultPort = 4000
|
||||
defaultHost = "localhost"
|
||||
defaultConfigPath = "./config.yml"
|
||||
configFileEnvVar = "BLOCKY_CONFIG_FILE"
|
||||
configFileEnvVarOld = "CONFIG_FILE"
|
||||
)
|
||||
|
||||
// NewRootCommand creates a new root cli command instance
|
||||
|
@ -49,7 +51,8 @@ Complete documentation is available at https://github.com/0xERR0R/blocky`,
|
|||
NewVersionCommand(),
|
||||
newServeCommand(),
|
||||
newBlockingCommand(),
|
||||
NewListsCommand())
|
||||
NewListsCommand(),
|
||||
NewHealthcheckCommand())
|
||||
|
||||
return c
|
||||
}
|
||||
|
@ -64,6 +67,18 @@ func init() {
|
|||
}
|
||||
|
||||
func initConfig() {
|
||||
if configPath == defaultConfigPath {
|
||||
val, present := os.LookupEnv(configFileEnvVar)
|
||||
if present {
|
||||
configPath = val
|
||||
} else {
|
||||
val, present = os.LookupEnv(configFileEnvVarOld)
|
||||
if present {
|
||||
configPath = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cfg, err := config.LoadConfig(configPath, false)
|
||||
if err != nil {
|
||||
util.FatalOnError("unable to load configuration: ", err)
|
||||
|
|
|
@ -2,14 +2,17 @@ package cmd
|
|||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/0xERR0R/blocky/log"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
. "github.com/0xERR0R/blocky/helpertest"
|
||||
)
|
||||
|
||||
var _ = Describe("Version command", func() {
|
||||
var _ = Describe("root command", func() {
|
||||
When("Version command is called", func() {
|
||||
log.Log().ExitFunc = nil
|
||||
It("should execute without error", func() {
|
||||
|
@ -20,4 +23,51 @@ var _ = Describe("Version command", func() {
|
|||
Expect(err).Should(Succeed())
|
||||
})
|
||||
})
|
||||
When("Config provided", func() {
|
||||
var (
|
||||
tmpDir *TmpFolder
|
||||
tmpFile *TmpFile
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
configPath = defaultConfigPath
|
||||
|
||||
tmpDir = NewTmpFolder("RootCommand")
|
||||
Expect(tmpDir.Error).Should(Succeed())
|
||||
DeferCleanup(tmpDir.Clean)
|
||||
|
||||
tmpFile = tmpDir.CreateStringFile("config",
|
||||
"upstream:",
|
||||
" default:",
|
||||
" - 1.1.1.1",
|
||||
"blocking:",
|
||||
" blackLists:",
|
||||
" ads:",
|
||||
" - https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt",
|
||||
" clientGroupsBlock:",
|
||||
" default:",
|
||||
" - ads",
|
||||
"port: 5333",
|
||||
)
|
||||
Expect(tmpFile.Error).Should(Succeed())
|
||||
})
|
||||
|
||||
It("should accept old env var", func() {
|
||||
os.Setenv(configFileEnvVarOld, tmpFile.Path)
|
||||
DeferCleanup(func() { os.Unsetenv(configFileEnvVarOld) })
|
||||
|
||||
initConfig()
|
||||
|
||||
Expect(configPath).Should(Equal(tmpFile.Path))
|
||||
})
|
||||
|
||||
It("should accept new env var", func() {
|
||||
os.Setenv(configFileEnvVar, tmpFile.Path)
|
||||
DeferCleanup(func() { os.Unsetenv(configFileEnvVar) })
|
||||
|
||||
initConfig()
|
||||
|
||||
Expect(configPath).Should(Equal(tmpFile.Path))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
3
go.mod
3
go.mod
|
@ -183,6 +183,7 @@ require (
|
|||
github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5 // indirect
|
||||
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect
|
||||
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
|
||||
github.com/ramr/go-reaper v0.2.1
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/ryancurrah/gomodguard v1.2.4 // indirect
|
||||
github.com/ryanrolds/sqlclosecheck v0.3.0 // indirect
|
||||
|
@ -242,3 +243,5 @@ require (
|
|||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect
|
||||
mvdan.cc/unparam v0.0.0-20220706161116-678bad134442 // indirect
|
||||
)
|
||||
|
||||
require github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||
|
|
2
go.sum
2
go.sum
|
@ -610,6 +610,8 @@ github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 h1:L8QM9bvf
|
|||
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
|
||||
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs=
|
||||
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ=
|
||||
github.com/ramr/go-reaper v0.2.1 h1:zww+wlQOvTjBZuk1920R/e0GFEb6O7+B0WQLV6dM924=
|
||||
github.com/ramr/go-reaper v0.2.1/go.mod h1:AVypdzrcCXjSc/JYnlXl8TsB+z84WyFzxWE8Jh0MOJc=
|
||||
github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "time/tzdata"
|
||||
|
||||
reaper "github.com/ramr/go-reaper"
|
||||
)
|
||||
|
||||
//nolint:gochecknoinits
|
||||
func init() {
|
||||
go reaper.Reap()
|
||||
}
|
Loading…
Reference in New Issue