SpoofDPI/test/configuration.go
2024-08-21 04:22:36 +05:00

225 lines
4.8 KiB
Go

package test
import (
"archive/tar"
"bytes"
"context"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/docker/docker/api/types/container"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
)
import "github.com/docker/docker/api/types/network"
const proxyDockerfile = `
FROM golang:alpine as builder
WORKDIR /SpoofDPI
COPY . .
RUN go build -o spoof-dpi ./cmd/spoof-dpi/main.go
FROM alpine:latest
WORKDIR /
COPY --from=builder /SpoofDPI/spoof-dpi .
`
type TarConsumer interface {
Accept(t *tar.Writer) error
}
type TarConsumerFn func(*tar.Writer) error
func (f TarConsumerFn) Accept(t *tar.Writer) error {
return f(t)
}
type FilePredicate interface {
Test(info FileInfo) bool
}
type FileInfo struct {
AbsPath string
Info fs.FileInfo
}
type FilePredicateFn func(info FileInfo) bool
func (f FilePredicateFn) Test(info FileInfo) bool {
return f(info)
}
func WriteHeaderAndContent(t *tar.Writer, h *tar.Header, content []byte) error {
if err := t.WriteHeader(h); err != nil {
return err
}
if _, err := t.Write(content); err != nil {
return err
}
return nil
}
func WriteFile(t *tar.Writer, mode int64, name string, size int64, file io.Reader) error {
hdr := &tar.Header{
Name: name,
Mode: mode,
Size: size,
Typeflag: tar.TypeReg,
Format: tar.FormatGNU,
}
if content, err := io.ReadAll(file); err == nil {
if err := WriteHeaderAndContent(t, hdr, content); err != nil {
return err
}
} else {
return err
}
return nil
}
func WriteDir(t *tar.Writer, mode int64, dirName string) error {
return WriteHeaderAndContent(t, &tar.Header{
Mode: int64(os.FileMode(mode) | os.ModeDir),
Name: dirName,
Size: 0,
}, nil)
}
func MakeTar(sourceDir string, filePredicate FilePredicate, consumers ...TarConsumer) (io.Reader, error) {
absSourceDir, err := filepath.Abs(sourceDir)
if err != nil {
return nil, err
}
filechan := make(chan FileInfo)
walkCtx, cancelWalk := context.WithCancel(context.Background())
defer cancelWalk()
go func() {
filepath.Walk(sourceDir, func(path string, info fs.FileInfo, err error) error {
abs, err := filepath.Abs(path)
if err != nil {
return err
}
select {
case filechan <- FileInfo{
Info: info,
AbsPath: abs,
}:
case <-walkCtx.Done():
return fmt.Errorf("canceled")
}
return nil
})
close(filechan)
}()
var buf bytes.Buffer
t := tar.NewWriter(&buf)
for f := range filechan {
if !(filePredicate.Test(f)) {
continue
}
info := f.Info
absFilePath := f.AbsPath
relName, err := filepath.Rel(absSourceDir, absFilePath)
if err != nil {
return nil, err
}
if info.IsDir() {
if err := WriteDir(t, int64(info.Mode()), relName); err != nil {
return nil, err
}
} else {
file, err := os.OpenFile(absFilePath, os.O_RDONLY, 0644)
if err != nil {
return nil, err
}
if err = WriteFile(t, int64(info.Mode()), relName, info.Size(), file); err != nil {
return nil, err
}
}
}
for _, consumer := range consumers {
err := consumer.Accept(t)
if err != nil {
return nil, err
}
}
if err := t.Close(); err != nil {
return nil, err
}
return bytes.NewReader(buf.Bytes()), nil
}
type Logging interface {
Printf(format string, v ...interface{})
}
func SpoofDPIContainer(port uint16, log Logging, proxyRunArgs []string) (testcontainers.Container, error) {
ctx := context.Background()
projectTar, err := MakeTar("../", FilePredicateFn(func(i FileInfo) bool {
if i.Info.IsDir() {
return false
}
if strings.Contains(i.AbsPath, ".git") {
return false
}
if strings.Contains(i.AbsPath, "Dockerfile") {
return false
}
if strings.Contains(i.AbsPath, ".idea") {
return false
}
return true
}), TarConsumerFn(func(writer *tar.Writer) error {
return WriteFile(writer, 0644, "Dockerfile", int64(len(proxyDockerfile)), strings.NewReader(proxyDockerfile))
}))
if err != nil {
return nil, err
}
cmd := []string{"./spoof-dpi"}
cmd = append(cmd, "-port", strconv.Itoa(int(port)))
cmd = append(cmd, proxyRunArgs...)
c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
FromDockerfile: testcontainers.FromDockerfile{
Tag: "spoof-dpi",
Repo: "spoof-dpi",
PrintBuildLog: true,
ContextArchive: projectTar,
Dockerfile: "Dockerfile",
KeepImage: true,
},
WaitingFor: wait.ForLog("[PROXY]").WithOccurrence(1),
Cmd: cmd,
LogConsumerCfg: &testcontainers.LogConsumerConfig{
Consumers: []testcontainers.LogConsumer{
&testcontainers.StdoutLogConsumer{},
},
},
HostConfigModifier: func(config *container.HostConfig) {
config.NetworkMode = network.NetworkHost
},
},
Logger: log,
})
if err != nil {
return nil, err
}
return c, nil
}