import from minilb repo

This commit is contained in:
2026-03-25 16:55:28 +02:00
parent 8efe7090be
commit 3aa1e52a5d
37 changed files with 1977 additions and 424 deletions

View File

@@ -25,7 +25,12 @@ minilbctl_SOURCES = \
cmd/minilbctl/main.go cmd/minilbctl/main.go
EXTRA_minilbctl_SOURCES = \ EXTRA_minilbctl_SOURCES = \
cmd/minilbctl/service/srvcmd.go cmd/minilbctl/service/srvcmd.go \
cmd/minilbctl/forwarder/listforw.go \
cmd/minilbctl/forwarder/deleteforw.go \
cmd/minilbctl/forwarder/createforw.go \
cmd/minilbctl/forwarder/forwcmd.go
minilbctl$(EXEEXT): $(minilbctl_SOURCES) $(EXTRA_minilbctl_SOURCES) $(EXTRA_minilbd_SOURCES) minilbctl$(EXEEXT): $(minilbctl_SOURCES) $(EXTRA_minilbctl_SOURCES) $(EXTRA_minilbd_SOURCES)
env CGO_ENABLED=0 $(GO) build $(GOFLAGS) -o minilbctl$(EXEEXT) $(minilbctl_SOURCES) env CGO_ENABLED=0 $(GO) build $(GOFLAGS) -o minilbctl$(EXEEXT) $(minilbctl_SOURCES)
@@ -82,14 +87,28 @@ EXTRA_DIST = \
vendor/* vendor/*
SYSTEMD_LIBDIR = /lib/systemd/system FREEBSD_LOCALBASE = /usr/local
FREEBSD_RCDIR = $(FREEBSD_LOCALBASE)/etc/rc.d
LINUX_SYSTEMDDIR = /lib/systemd/system
install-data-local: install-data-local:
test -z $(DESTDIR)$(srv_confdir) || $(MKDIR_P) $(DESTDIR)$(srv_confdir) test -z $(DESTDIR)$(srv_confdir) || $(MKDIR_P) $(DESTDIR)$(srv_confdir)
test -z $(DESTDIR)$(srv_logdir) || $(MKDIR_P) $(DESTDIR)$(srv_logdir) test -z $(DESTDIR)$(srv_logdir) || $(MKDIR_P) $(DESTDIR)$(srv_logdir)
test -z $(DESTDIR)$(srv_rundir) || $(MKDIR_P) $(DESTDIR)$(srv_rundir) test -z $(DESTDIR)$(srv_rundir) || $(MKDIR_P) $(DESTDIR)$(srv_rundir)
test -z $(DESTDIR)$(SYSTEMD_LIBDIR) || $(MKDIR_P) $(DESTDIR)$(SYSTEMD_LIBDIR) test -z $(DESTDIR)$(SYSTEMD_LIBDIR) || $(MKDIR_P) $(DESTDIR)$(SYSTEMD_LIBDIR)
$(INSTALL_DATA) initrc/minilbd.service $(DESTDIR)$(SYSTEMD_LIBDIR) if FREEBSD_OS
test -z $(DESTDIR)$(FREEBSD_RCDIR) || $(MKDIR_P) $(DESTDIR)$(FREEBSD_RCDIR)
$(INSTALL_DATA) initrc/minilbd $(DESTDIR)$(FREEBSD_RCDIR)
chmod a+x $(DESTDIR)$(FREEBSD_RCDIR)/minilbd
endif
if LINUX_OS
if SYSTEMD
test -z $(DESTDIR)$(LINUX_SYSTEMDDIR) || $(MKDIR_P) $(DESTDIR)$(LINUX_SYSTEMDDIR)
$(INSTALL_DATA) initrc/minilbd.service $(DESTDIR)$(LINUX_SYSTEMDDIR)
endif
endif
GENDIR=pkg/mlbctl GENDIR=pkg/mlbctl
grpc: grpc:

View File

@@ -103,7 +103,7 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno config.status.lineno configure.lineno config.status.lineno
mkinstalldirs = $(install_sh) -d mkinstalldirs = $(install_sh) -d
CONFIG_CLEAN_FILES = app/config/variant.go initrc/minilbd.service \ CONFIG_CLEAN_FILES = app/config/variant.go initrc/minilbd.service \
debian/control debian/changelog initrc/minilbd debian/control debian/changelog
CONFIG_CLEAN_VPATH_FILES = CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)"
PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS) PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS)
@@ -176,6 +176,7 @@ am__DIST_COMMON = $(srcdir)/Makefile.in \
$(top_srcdir)/app/config/variant.go.in \ $(top_srcdir)/app/config/variant.go.in \
$(top_srcdir)/debian/changelog.in \ $(top_srcdir)/debian/changelog.in \
$(top_srcdir)/debian/control.in \ $(top_srcdir)/debian/control.in \
$(top_srcdir)/initrc/minilbd.in \
$(top_srcdir)/initrc/minilbd.service.in README.md config.guess \ $(top_srcdir)/initrc/minilbd.service.in README.md config.guess \
config.sub install-sh missing config.sub install-sh missing
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -242,7 +243,9 @@ PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@ PATH_SEPARATOR = @PATH_SEPARATOR@
PODMAN = @PODMAN@ PODMAN = @PODMAN@
PROTOC = @PROTOC@
ROOT_GROUP = @ROOT_GROUP@ ROOT_GROUP = @ROOT_GROUP@
RUN_USER = @RUN_USER@
SET_MAKE = @SET_MAKE@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@ SHELL = @SHELL@
SORT = @SORT@ SORT = @SORT@
@@ -292,16 +295,19 @@ pdfdir = @pdfdir@
prefix = @prefix@ prefix = @prefix@
program_transform_name = @program_transform_name@ program_transform_name = @program_transform_name@
psdir = @psdir@ psdir = @psdir@
run_user = @run_user@
runstatedir = @runstatedir@ runstatedir = @runstatedir@
sbindir = @sbindir@ sbindir = @sbindir@
sharedstatedir = @sharedstatedir@ sharedstatedir = @sharedstatedir@
srcdir = @srcdir@ srcdir = @srcdir@
srv_bindir = @srv_bindir@
srv_confdir = @srv_confdir@ srv_confdir = @srv_confdir@
srv_datadir = @srv_datadir@ srv_datadir = @srv_datadir@
srv_devel_mode = @srv_devel_mode@ srv_devel_mode = @srv_devel_mode@
srv_libdir = @srv_libdir@ srv_libdir = @srv_libdir@
srv_logdir = @srv_logdir@ srv_logdir = @srv_logdir@
srv_rundir = @srv_rundir@ srv_rundir = @srv_rundir@
srv_sbindir = @srv_sbindir@
srv_sharedir = @srv_sharedir@ srv_sharedir = @srv_sharedir@
sysconfdir = @sysconfdir@ sysconfdir = @sysconfdir@
target_alias = @target_alias@ target_alias = @target_alias@
@@ -325,7 +331,11 @@ minilbctl_SOURCES = \
cmd/minilbctl/main.go cmd/minilbctl/main.go
EXTRA_minilbctl_SOURCES = \ EXTRA_minilbctl_SOURCES = \
cmd/minilbctl/service/srvcmd.go cmd/minilbctl/service/srvcmd.go \
cmd/minilbctl/forwarder/listforw.go \
cmd/minilbctl/forwarder/deleteforw.go \
cmd/minilbctl/forwarder/createforw.go \
cmd/minilbctl/forwarder/forwcmd.go
minilbd_SOURCES = \ minilbd_SOURCES = \
cmd/minilbd/main.go cmd/minilbd/main.go
@@ -363,7 +373,9 @@ EXTRA_DIST = \
README.md \ README.md \
vendor/* vendor/*
SYSTEMD_LIBDIR = /lib/systemd/system FREEBSD_LOCALBASE = /usr/local
FREEBSD_RCDIR = $(FREEBSD_LOCALBASE)/etc/rc.d
LINUX_SYSTEMDDIR = /lib/systemd/system
GENDIR = pkg/mlbctl GENDIR = pkg/mlbctl
BUILD_DIR = $(shell pwd)/TMP.build BUILD_DIR = $(shell pwd)/TMP.build
DIST_DIR = $(shell pwd)/DIST DIST_DIR = $(shell pwd)/DIST
@@ -409,6 +421,8 @@ app/config/variant.go: $(top_builddir)/config.status $(top_srcdir)/app/config/va
cd $(top_builddir) && $(SHELL) ./config.status $@ cd $(top_builddir) && $(SHELL) ./config.status $@
initrc/minilbd.service: $(top_builddir)/config.status $(top_srcdir)/initrc/minilbd.service.in initrc/minilbd.service: $(top_builddir)/config.status $(top_srcdir)/initrc/minilbd.service.in
cd $(top_builddir) && $(SHELL) ./config.status $@ cd $(top_builddir) && $(SHELL) ./config.status $@
initrc/minilbd: $(top_builddir)/config.status $(top_srcdir)/initrc/minilbd.in
cd $(top_builddir) && $(SHELL) ./config.status $@
debian/control: $(top_builddir)/config.status $(top_srcdir)/debian/control.in debian/control: $(top_builddir)/config.status $(top_srcdir)/debian/control.in
cd $(top_builddir) && $(SHELL) ./config.status $@ cd $(top_builddir) && $(SHELL) ./config.status $@
debian/changelog: $(top_builddir)/config.status $(top_srcdir)/debian/changelog.in debian/changelog: $(top_builddir)/config.status $(top_srcdir)/debian/changelog.in
@@ -879,7 +893,11 @@ install-data-local:
test -z $(DESTDIR)$(srv_logdir) || $(MKDIR_P) $(DESTDIR)$(srv_logdir) test -z $(DESTDIR)$(srv_logdir) || $(MKDIR_P) $(DESTDIR)$(srv_logdir)
test -z $(DESTDIR)$(srv_rundir) || $(MKDIR_P) $(DESTDIR)$(srv_rundir) test -z $(DESTDIR)$(srv_rundir) || $(MKDIR_P) $(DESTDIR)$(srv_rundir)
test -z $(DESTDIR)$(SYSTEMD_LIBDIR) || $(MKDIR_P) $(DESTDIR)$(SYSTEMD_LIBDIR) test -z $(DESTDIR)$(SYSTEMD_LIBDIR) || $(MKDIR_P) $(DESTDIR)$(SYSTEMD_LIBDIR)
$(INSTALL_DATA) initrc/minilbd.service $(DESTDIR)$(SYSTEMD_LIBDIR) @FREEBSD_OS_TRUE@ test -z $(DESTDIR)$(FREEBSD_RCDIR) || $(MKDIR_P) $(DESTDIR)$(FREEBSD_RCDIR)
@FREEBSD_OS_TRUE@ $(INSTALL_DATA) initrc/minilbd $(DESTDIR)$(FREEBSD_RCDIR)
@FREEBSD_OS_TRUE@ chmod a+x $(DESTDIR)$(FREEBSD_RCDIR)/minilbd
@LINUX_OS_TRUE@@SYSTEMD_TRUE@ test -z $(DESTDIR)$(LINUX_SYSTEMDDIR) || $(MKDIR_P) $(DESTDIR)$(LINUX_SYSTEMDDIR)
@LINUX_OS_TRUE@@SYSTEMD_TRUE@ $(INSTALL_DATA) initrc/minilbd.service $(DESTDIR)$(LINUX_SYSTEMDDIR)
grpc: grpc:
mkdir -p $(GENDIR) mkdir -p $(GENDIR)
$(PROTOC) --proto_path=proto --go_out=$(GENDIR) --go-grpc_out=$(GENDIR) proto/mlbctl.proto $(PROTOC) --proto_path=proto --go_out=$(GENDIR) --go-grpc_out=$(GENDIR) proto/mlbctl.proto

View File

@@ -36,6 +36,7 @@ type Config struct {
RunPath string `json:"runfile" yaml:"runfile"` RunPath string `json:"runfile" yaml:"runfile"`
AsDaemon bool `json:"asDaemon" yaml:"asDaemon"` AsDaemon bool `json:"asDaemon" yaml:"asDaemon"`
LogLimit int64 `json:"logLimit" yaml:logLimit` LogLimit int64 `json:"logLimit" yaml:logLimit`
RunUser string `json:"runUser" yaml:runUser`
} }
func NewConfig() (*Config, error) { func NewConfig() (*Config, error) {
@@ -45,6 +46,7 @@ func NewConfig() (*Config, error) {
}, },
AsDaemon: false, AsDaemon: false,
LogLimit: 1024 * 1024 * 10, // 10 Mb LogLimit: 1024 * 1024 * 10, // 10 Mb
RunUser: "daemon",
} }
hostname, err := os.Hostname() hostname, err := os.Hostname()
if err != nil { if err != nil {

View File

@@ -1,9 +1,10 @@
package config package config
const ( const (
confdirPath = "/home/ziggi/Projects/gserver/etc/minilb" confdirPath = "/etc/minilb"
rundirPath = "/home/ziggi/Projects/gserver/tmp/run" rundirPath = "/var/run/minilb"
logdirPath = "/home/ziggi/Projects/gserver/tmp/log" logdirPath = "/var/log/minilb"
datadirPath = "/home/ziggi/Projects/gserver/tmp/data" datadirPath = "/var/lib/minilb"
packageVersion = "0.0.1" pkgVersion = "0.0.1"
runUser = "daemon"
) )

View File

@@ -1,10 +1,10 @@
package config package config
const ( const (
confdirPath = "@srv_confdir@" confdirPath = "@srv_confdir@"
rundirPath = "@srv_rundir@" rundirPath = "@srv_rundir@"
logdirPath = "@srv_logdir@" logdirPath = "@srv_logdir@"
datadirPath = "@srv_datadir@" datadirPath = "@srv_datadir@"
packageVersion = "@PACKAGE_VERSION@" pkgVersion = "@PACKAGE_VERSION@"
runUser = "@run_user@"
) )

View File

@@ -15,13 +15,13 @@ type HandlerConfig struct {
type Handler struct { type Handler struct {
mlbctl.UnimplementedControlServer mlbctl.UnimplementedControlServer
lg *operator.Operator oper *operator.Operator
log *logger.Logger log *logger.Logger
} }
func NewHandler(conf *HandlerConfig) *Handler { func NewHandler(conf *HandlerConfig) *Handler {
hand := Handler{ hand := Handler{
lg: conf.Operator, oper: conf.Operator,
} }
hand.log = logger.NewLogger("handler") hand.log = logger.NewLogger("handler")
return &hand return &hand

View File

@@ -9,6 +9,6 @@ import (
func (hand *Handler) GetHello(ctx context.Context, req *mlbctl.GetHelloParams) (*mlbctl.GetHelloResult, error) { func (hand *Handler) GetHello(ctx context.Context, req *mlbctl.GetHelloParams) (*mlbctl.GetHelloResult, error) {
var err error var err error
hand.log.Debugf("Handle getHello request") hand.log.Debugf("Handle getHello request")
res, err := hand.lg.GetHello(ctx, req) res, err := hand.oper.GetHello(ctx, req)
return res, err return res, err
} }

25
app/handler/proxy.go Normal file
View File

@@ -0,0 +1,25 @@
package handler
import (
"context"
"helmet/pkg/mlbctl"
)
func (hand *Handler) ListForwarders(ctx context.Context, req *mlbctl.ListForwardersParams) (*mlbctl.ListForwardersResult, error) {
var err error
res, err := hand.oper.ListForwarders(ctx, req)
return res, err
}
func (hand *Handler) CreateForwarder(ctx context.Context, req *mlbctl.CreateForwarderParams) (*mlbctl.CreateForwarderResult, error) {
var err error
res, err := hand.oper.CreateForwarder(ctx, req)
return res, err
}
func (hand *Handler) DeleteForwarder(ctx context.Context, req *mlbctl.DeleteForwarderParams) (*mlbctl.DeleteForwarderResult, error) {
var err error
res, err := hand.oper.DeleteForwarder(ctx, req)
return res, err
}

View File

@@ -4,6 +4,7 @@ import (
"helmet/app/logger" "helmet/app/logger"
"helmet/app/config" "helmet/app/config"
"helmet/app/rproxy"
) )
type OperatorConfig struct { type OperatorConfig struct {
@@ -13,13 +14,15 @@ type OperatorConfig struct {
type Operator struct { type Operator struct {
log *logger.Logger log *logger.Logger
auths []config.Auth auths []config.Auth
proxy *rproxy.Proxy
} }
func NewOperator(conf *OperatorConfig) (*Operator, error) { func NewOperator(conf *OperatorConfig) (*Operator, error) {
var err error var err error
lg := &Operator{ oper := &Operator{
auths: conf.Auths, auths: conf.Auths,
} }
lg.log = logger.NewLogger("operator") oper.log = logger.NewLogger("operator")
return lg, err oper.proxy = rproxy.NewProxy()
return oper, err
} }

44
app/operator/proxy.go Normal file
View File

@@ -0,0 +1,44 @@
package operator
import (
"context"
"helmet/pkg/mlbctl"
)
func (oper *Operator) ListForwarders(ctx context.Context, params *mlbctl.ListForwardersParams) (*mlbctl.ListForwardersResult, error) {
var err error
res := &mlbctl.ListForwardersResult{
Forwarders: make([]*mlbctl.Forwarder, 0),
}
for _, forw := range oper.proxy.Forwarders {
oForw := &mlbctl.Forwarder{
Lport: forw.Lport,
Dport: forw.Dport,
Destinations: make([]*mlbctl.Destination, 0),
}
for _, dest := range forw.Dests {
oDest := &mlbctl.Destination{
Address: dest.Address,
}
oForw.Destinations = append(oForw.Destinations, oDest)
}
res.Forwarders = append(res.Forwarders, oForw)
}
return res, err
}
func (oper *Operator) CreateForwarder(ctx context.Context, params *mlbctl.CreateForwarderParams) (*mlbctl.CreateForwarderResult, error) {
var err error
res := &mlbctl.CreateForwarderResult{}
err = oper.proxy.AddForwarder(ctx, params.Lport, params.Dport, params.Destinations...)
return res, err
}
func (oper *Operator) DeleteForwarder(ctx context.Context, params *mlbctl.DeleteForwarderParams) (*mlbctl.DeleteForwarderResult, error) {
var err error
res := &mlbctl.DeleteForwarderResult{}
err = oper.proxy.DeleteForwarder(ctx, params.Lport)
return res, err
}

192
app/rproxy/proxy.go Normal file
View File

@@ -0,0 +1,192 @@
package rproxy
import (
"context"
"errors"
"io"
"log"
"math/rand"
"net"
"strconv"
"sync"
)
type Proxy struct {
Forwarders []*Forwarder `json:"forwarders" yaml:"forwarders"`
ctx context.Context `json:"-" yaml:"-"`
cancel context.CancelFunc `json:"-" yaml:"-"`
wg sync.WaitGroup `json:"-" yaml:"-"`
}
func NewProxy() *Proxy {
ctx, cancel := context.WithCancel(context.Background())
return &Proxy{
Forwarders: make([]*Forwarder, 0),
ctx: ctx,
cancel: cancel,
}
}
func (bal *Proxy) AddForwarder(ctx context.Context, lport, dport uint32, addrs ...string) error {
var err error
forw, err := NewForwarder(ctx, lport, dport, addrs...)
if err != nil {
return err
}
bal.Forwarders = append(bal.Forwarders, forw)
bal.wg.Add(1)
go forw.Listen(&bal.wg)
return err
}
func (bal *Proxy) DeleteForwarder(ctx context.Context, lport uint32) error {
var err error
forwarders := make([]*Forwarder, 0)
for _, forw := range bal.Forwarders {
if forw.Lport == lport {
forw.Stop()
continue
}
forwarders = append(forwarders, forw)
}
bal.Forwarders = forwarders
return err
}
func (bal *Proxy) Start() error {
var err error
for _, forw := range bal.Forwarders {
bal.wg.Add(1)
go forw.Listen(&bal.wg)
}
bal.wg.Wait()
return err
}
func (bal *Proxy) Stop() error {
var err error
for _, forw := range bal.Forwarders {
forw.Stop()
}
return err
}
type Forwarder struct {
listen net.Listener `json:"-" yaml:"-"`
ctx context.Context `json:"-" yaml:"-"`
cancel context.CancelFunc `json:"-" yaml:"-"`
Lport uint32 `json:"lport" yaml:"lport"`
Dport uint32 `json:"dport" yaml:"dport"`
Dests []*Destination `json:"dests" yaml:"dests"`
}
func NewForwarder(ctx context.Context, lport, dport uint32, addrs ...string) (*Forwarder, error) {
ctx, cancel := context.WithCancel(ctx)
forw := &Forwarder{
Dests: make([]*Destination, 0),
Lport: lport,
Dport: dport,
ctx: ctx,
cancel: cancel,
}
for _, addr := range addrs {
dest := NewDestination(addr)
forw.Dests = append(forw.Dests, dest)
}
port := ":" + strconv.FormatUint(uint64(forw.Lport), 10)
listen, err := net.Listen("tcp", port)
if err != nil {
return forw, err
}
forw.listen = listen
return forw, err
}
func (forw *Forwarder) Listen(wg *sync.WaitGroup) {
log.Printf("Start listening on %d\n", forw.Lport)
defer wg.Done()
for {
conn, err := forw.listen.Accept()
if err != nil {
log.Printf("Listen err: %v\n", err)
return
}
go forw.handle(forw.ctx, conn)
}
}
func (forw *Forwarder) Stop() error {
return forw.listen.Close()
}
func (forw *Forwarder) handle(ctx context.Context, inconn net.Conn) {
log.Printf("Handler on %d started\n", forw.Lport)
defer inconn.Close()
if len(forw.Dests) == 0 {
return
}
addrnum := rand.Uint32() % uint32(len(forw.Dests))
ipaddr := forw.Dests[addrnum].Address
dstaddr := ipaddr + ":" + strconv.FormatUint(uint64(forw.Dport), 10)
outconn, err := net.Dial("tcp", dstaddr)
if err != nil {
return
}
var wg sync.WaitGroup
wg.Add(1)
go forw.stream(&wg, inconn, outconn)
wg.Add(1)
go forw.stream(&wg, outconn, inconn)
wg.Wait()
log.Printf("Handler on %d stopped\n", forw.Lport)
}
func (forw *Forwarder) stream(wg *sync.WaitGroup, inconn io.Reader, outconn io.Writer) {
defer wg.Done()
_, err := copy(forw.ctx, outconn, inconn)
if err != nil {
log.Printf("Copy err: %v\n", err)
}
}
type Destination struct {
Address string `json:"address" yaml:"address"`
}
func NewDestination(addr string) *Destination {
return &Destination{
Address: addr,
}
}
func copy(ctx context.Context, writer io.Writer, reader io.Reader) (int64, error) {
var err error
var size int64
var halt bool
buffer := make([]byte, 1024*4)
for {
select {
case <-ctx.Done():
err = errors.New("Break copy by context")
break
default:
}
rsize, err := reader.Read(buffer)
if err == io.EOF {
err = nil
halt = true
}
if err != nil {
return size, err
}
wsize, err := writer.Write(buffer[0:rsize])
size += int64(wsize)
if err != nil {
return size, err
}
if halt {
break
}
}
return size, err
}

View File

@@ -3,6 +3,7 @@ package server
import ( import (
"context" "context"
"fmt" "fmt"
"net"
"os" "os"
"os/signal" "os/signal"
"os/user" "os/user"
@@ -17,6 +18,7 @@ import (
"helmet/app/logger" "helmet/app/logger"
"helmet/app/operator" "helmet/app/operator"
"helmet/app/service" "helmet/app/service"
"helmet/pkg/network"
"helmet/pkg/x509crt" "helmet/pkg/x509crt"
) )
@@ -32,6 +34,7 @@ type Server struct {
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
wg sync.WaitGroup wg sync.WaitGroup
listen net.Listener
} }
func NewServer() (*Server, error) { func NewServer() (*Server, error) {
@@ -66,23 +69,66 @@ func (srv *Server) Build() error {
var err error var err error
srv.log.Infof("Build server") srv.log.Infof("Build server")
// Get effective user uid/guid
usr, err := user.Lookup(srv.conf.RunUser)
if err != nil {
return err
}
uid64, err := strconv.ParseInt(usr.Uid, 10, 64)
if err != nil {
return err
}
gid64, err := strconv.ParseInt(usr.Gid, 10, 64)
if err != nil {
return err
}
uid := int(uid64)
gid := int(gid64)
if srv.conf.AsDaemon { if srv.conf.AsDaemon {
logDir := filepath.Dir(srv.conf.LogPath) logDir := filepath.Dir(srv.conf.LogPath)
srv.log.Infof("Create %s dir", logDir) srv.log.Infof("Create log dir: %s", logDir)
err = os.MkdirAll(logDir, 0750) err = os.MkdirAll(logDir, 0750)
if err != nil { if err != nil {
return err return err
} }
err = os.Chown(logDir, uid, gid)
if err != nil {
return err
}
runDir := filepath.Dir(srv.conf.RunPath) runDir := filepath.Dir(srv.conf.RunPath)
srv.log.Infof("Create %s dir", runDir) srv.log.Infof("Create run dir: %s", runDir)
err = os.MkdirAll(runDir, 0750) err = os.MkdirAll(runDir, 0750)
if err != nil { if err != nil {
return err return err
} }
err = os.Chown(runDir, uid, gid)
if err != nil {
return err
}
} }
// Create listener
addrinfo := ":" + strconv.FormatUint(uint64(srv.conf.Service.Port), 10)
listener, err := network.CreateListener(addrinfo)
if err != nil {
return err
}
srv.listen = listener
// Change effective user
err = syscall.Setuid(uid)
if err != nil {
return err
}
uidstr := strconv.FormatInt(int64(syscall.Geteuid()), 10)
usr, err = user.LookupId(uidstr)
if err != nil {
return err
}
srv.log.Warningf("Now run as user: %s", usr.Username)
// Create X509 certs // Create X509 certs
srv.x509cert, srv.x509key, err = x509crt.CreateX509SelfSignedCert(srv.conf.Hostname) srv.x509cert, srv.x509key, err = x509crt.CreateCertKey(srv.conf.Hostname)
if err != nil { if err != nil {
return err return err
} }
@@ -103,8 +149,7 @@ func (srv *Server) Build() error {
// Create service // Create service
serviceConfig := &service.ServiceConfig{ serviceConfig := &service.ServiceConfig{
PortNum: srv.conf.Service.Port, Listener: srv.listen,
Hostname: srv.conf.Hostname,
Handler: srv.hand, Handler: srv.hand,
Operator: srv.oper, Operator: srv.oper,
X509Cert: srv.x509cert, X509Cert: srv.x509cert,
@@ -123,86 +168,21 @@ func (srv *Server) Run() error {
return err return err
} }
srv.log.Debugf("Server configuration:\n%s\n", yamlConfig) srv.log.Debugf("Server configuration:\n%s\n", yamlConfig)
srv.ctx, srv.cancel = context.WithCancel(context.Background()) srv.ctx, srv.cancel = context.WithCancel(context.Background())
currUser, err := user.Current() currUser, err := user.Current()
if err != nil { if err != nil {
return err return err
} }
srv.log.Infof("Running server as user %s", currUser.Username) srv.log.Infof("Start server as user %s", currUser.Username)
uidstr := strconv.FormatInt(int64(syscall.Geteuid()), 10)
sigs := make(chan os.Signal, 1) usr, err := user.LookupId(uidstr)
done := make(chan error, 1) if err != nil {
return err
// Run service
startService := func(svc *service.Service, done chan error) {
err = svc.Run()
if err != nil {
srv.log.Errorf("Service error: %v", err)
done <- err
}
} }
go startService(srv.svc, done) srv.log.Infof("Run server as user %s", usr.Username)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
var signal os.Signal
select {
case signal = <-sigs:
srv.log.Infof("Services stopped by signal: %v", signal)
srv.cancel()
srv.svc.Stop()
srv.wg.Wait()
}
return err
}
func (srv *Server) PseudoFork() error {
const successExit int = 0
var keyEnv string = "IMX0LTSELMRF8K"
var err error
_, isChild := os.LookupEnv(keyEnv)
switch {
case !isChild:
os.Setenv(keyEnv, "TRUE")
procAttr := syscall.ProcAttr{}
cwd, err := os.Getwd()
if err != nil {
return err
}
var sysFiles = make([]uintptr, 3)
sysFiles[0] = uintptr(syscall.Stdin)
sysFiles[1] = uintptr(syscall.Stdout)
sysFiles[2] = uintptr(syscall.Stderr)
procAttr.Files = sysFiles
procAttr.Env = os.Environ()
procAttr.Dir = cwd
_, err = syscall.ForkExec(os.Args[0], os.Args, &procAttr)
if err != nil {
return err
}
os.Exit(successExit)
case isChild:
_, err = syscall.Setsid()
if err != nil {
return err
}
}
os.Unsetenv(keyEnv)
return err
}
func (srv *Server) Daemonize() error {
var err error
if srv.conf.AsDaemon { if srv.conf.AsDaemon {
// Restart process process
err = srv.PseudoFork()
if err != nil {
return err
}
// Redirect stdin // Redirect stdin
nullFile, err := os.OpenFile("/dev/null", os.O_RDWR, 0) nullFile, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
if err != nil { if err != nil {
@@ -232,11 +212,6 @@ func (srv *Server) Daemonize() error {
} }
srv.logf = logFile srv.logf = logFile
// Write process ID // Write process ID
rundir := filepath.Dir(srv.conf.RunPath)
err = os.MkdirAll(rundir, 0750)
if err != nil {
return err
}
pidFile, err := os.OpenFile(srv.conf.RunPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640) pidFile, err := os.OpenFile(srv.conf.RunPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640)
if err != nil { if err != nil {
return err return err
@@ -248,13 +223,51 @@ func (srv *Server) Daemonize() error {
return err return err
} }
} }
sigs := make(chan os.Signal, 1)
done := make(chan error, 1)
// Run service
startService := func(svc *service.Service, done chan error) {
err = svc.Run()
if err != nil {
srv.log.Errorf("Service error: %v", err)
done <- err
}
}
go startService(srv.svc, done)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
var signal os.Signal
select {
case signal = <-sigs:
srv.log.Infof("Services stopped by signal: %v", signal)
srv.cancel()
srv.svc.Stop()
srv.wg.Wait()
}
return err return err
} }
func (srv *Server) Rotator() { func (srv *Server) Daemonize() error {
var err error
if srv.conf.AsDaemon {
// Restart process process
err = srv.pseudoFork()
if err != nil {
return err
}
}
return err
}
func (srv *Server) logRotator() {
// TODO: integrate into logger
srv.wg.Add(1) srv.wg.Add(1)
var counter uint64
logFunc := func() { logFunc := func() {
for { for {
counter += 1
select { select {
case <-srv.ctx.Done(): case <-srv.ctx.Done():
srv.wg.Done() srv.wg.Done()
@@ -262,26 +275,64 @@ func (srv *Server) Rotator() {
return return
default: default:
} }
stat, err := srv.logf.Stat() if (counter % 60) == 1 {
if err == nil && stat.Size() > srv.conf.LogLimit { stat, err := srv.logf.Stat()
srv.log.Infof("Rotate log file") if err == nil && stat.Size() > srv.conf.LogLimit {
countFiles := 3 srv.log.Infof("Rotate log file")
for i := 1; i < countFiles; i++ { countFiles := 3
nextName := fmt.Sprintf("%s.%d", srv.conf.LogPath, i+1) for i := 1; i < countFiles; i++ {
prevName := fmt.Sprintf("%s.%d", srv.conf.LogPath, i) nextName := fmt.Sprintf("%s.%d", srv.conf.LogPath, i+1)
os.Rename(prevName, nextName) prevName := fmt.Sprintf("%s.%d", srv.conf.LogPath, i)
} os.Rename(prevName, nextName)
os.Rename(srv.conf.LogPath, srv.conf.LogPath+".1") }
logFile, err := os.OpenFile(srv.conf.LogPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0640) os.Rename(srv.conf.LogPath, srv.conf.LogPath+".1")
if err == nil { logFile, err := os.OpenFile(srv.conf.LogPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0640)
syscall.Dup2(int(logFile.Fd()), int(os.Stdout.Fd())) if err == nil {
syscall.Dup2(int(logFile.Fd()), int(os.Stderr.Fd())) syscall.Dup2(int(logFile.Fd()), int(os.Stdout.Fd()))
srv.logf.Close() syscall.Dup2(int(logFile.Fd()), int(os.Stderr.Fd()))
srv.logf = logFile srv.logf.Close()
srv.logf = logFile
}
} }
} }
time.Sleep(3 * time.Second) time.Sleep(1 * time.Second)
} }
} }
go logFunc() go logFunc()
} }
func (srv *Server) pseudoFork() error {
const successExit int = 0
var keyEnv string = "IMX0LTSELMRF8K"
var err error
_, isChild := os.LookupEnv(keyEnv)
switch {
case !isChild:
os.Setenv(keyEnv, "TRUE")
procAttr := syscall.ProcAttr{}
cwd, err := os.Getwd()
if err != nil {
return err
}
var sysFiles = make([]uintptr, 3)
sysFiles[0] = uintptr(syscall.Stdin)
sysFiles[1] = uintptr(syscall.Stdout)
sysFiles[2] = uintptr(syscall.Stderr)
procAttr.Files = sysFiles
procAttr.Env = os.Environ()
procAttr.Dir = cwd
_, err = syscall.ForkExec(os.Args[0], os.Args, &procAttr)
if err != nil {
return err
}
os.Exit(successExit)
case isChild:
_, err = syscall.Setsid()
if err != nil {
return err
}
}
os.Unsetenv(keyEnv)
return err
}

View File

@@ -4,12 +4,10 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"encoding/json" "encoding/json"
"fmt"
"net" "net"
"helmet/app/logger"
"helmet/app/handler" "helmet/app/handler"
"helmet/app/logger"
"helmet/app/operator" "helmet/app/operator"
"google.golang.org/grpc" "google.golang.org/grpc"
@@ -22,8 +20,7 @@ import (
type ServiceConfig struct { type ServiceConfig struct {
Handler *handler.Handler Handler *handler.Handler
Operator *operator.Operator Operator *operator.Operator
PortNum uint32 Listener net.Listener
Hostname string
X509Cert []byte X509Cert []byte
X509Key []byte X509Key []byte
} }
@@ -33,11 +30,7 @@ type Service struct {
hand *handler.Handler hand *handler.Handler
oper *operator.Operator oper *operator.Operator
log *logger.Logger log *logger.Logger
portnum uint32 listen net.Listener
hostname string
username string
password string
x509Cert []byte x509Cert []byte
x509Key []byte x509Key []byte
} }
@@ -46,8 +39,7 @@ func NewService(conf *ServiceConfig) *Service {
svc := Service{ svc := Service{
hand: conf.Handler, hand: conf.Handler,
oper: conf.Operator, oper: conf.Operator,
portnum: conf.PortNum, listen: conf.Listener,
hostname: conf.Hostname,
x509Cert: conf.X509Cert, x509Cert: conf.X509Cert,
x509Key: conf.X509Key, x509Key: conf.X509Key,
} }
@@ -60,12 +52,6 @@ func (svc *Service) Run() error {
var err error var err error
svc.log.Infof("Service run") svc.log.Infof("Service run")
listenSpec := fmt.Sprintf(":%d", svc.portnum)
listener, err := net.Listen("tcp", listenSpec)
if err != nil {
return err
}
tlsCert, err := tls.X509KeyPair(svc.x509Cert, svc.x509Key) tlsCert, err := tls.X509KeyPair(svc.x509Cert, svc.x509Key)
if err != nil { if err != nil {
return err return err
@@ -75,7 +61,6 @@ func (svc *Service) Run() error {
ClientAuth: tls.NoClientCert, ClientAuth: tls.NoClientCert,
InsecureSkipVerify: true, InsecureSkipVerify: true,
} }
tlsCredentials := credentials.NewTLS(&tlsConfig) tlsCredentials := credentials.NewTLS(&tlsConfig)
if err != nil { if err != nil {
return err return err
@@ -87,14 +72,13 @@ func (svc *Service) Run() error {
gsrvOpts := []grpc.ServerOption{ gsrvOpts := []grpc.ServerOption{
grpc.Creds(tlsCredentials), grpc.Creds(tlsCredentials),
grpc.ChainUnaryInterceptor(interceptors...), grpc.ChainUnaryInterceptor(interceptors...),
//grpc.UnaryInterceptor(svc.authInterceptor),
} }
svc.gsrv = grpc.NewServer(gsrvOpts...) svc.gsrv = grpc.NewServer(gsrvOpts...)
svc.hand.Register(svc.gsrv) svc.hand.Register(svc.gsrv)
svc.log.Infof("Service listening at %v", listener.Addr()) svc.log.Infof("Service listening at %v", svc.listen.Addr())
err = svc.gsrv.Serve(listener) err = svc.gsrv.Serve(svc.listen)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -0,0 +1,117 @@
package hash
import (
"fmt"
"helmet/pkg/passwd"
"github.com/spf13/cobra"
"sigs.k8s.io/yaml"
)
type Tool struct {
cmd *cobra.Command
createHashParams CreateHashParams
checkHashParams CheckHashParams
}
func NewTool() *Tool {
tool := &Tool{}
tool.cmd = &cobra.Command{
Use: "hash",
Short: "Hash opeation",
}
createHashCmd := &cobra.Command{
Use: "create password",
Args: cobra.ExactArgs(1),
Short: "Create authentification hash",
RunE: tool.CreateHash,
}
checkHashCmd := &cobra.Command{
Use: "check password hash",
Args: cobra.ExactArgs(2),
Short: "Check authentification hash",
RunE: tool.CheckHash,
}
tool.cmd.AddCommand(createHashCmd)
tool.cmd.AddCommand(checkHashCmd)
return tool
}
func (tool *Tool) GetCmd() *cobra.Command {
return tool.cmd
}
type CreateHashParams struct {
Password string
}
type CreateHashResult struct {
Hash string `json:"hash"`
}
func (tool *Tool) CreateHash(cmd *cobra.Command, args []string) error {
tool.createHashParams.Password = args[0]
res, err := tool.createHash(&tool.createHashParams)
printResponse(res, err)
return err
}
func (tool *Tool) createHash(params *CreateHashParams) (*CreateHashResult, error) {
var err error
res := &CreateHashResult{}
if params.Password == "" {
err = fmt.Errorf("Empty password")
return res, err
}
res.Hash = passwd.MakeSHA256Hash([]byte(params.Password))
if !passwd.PasswordMatch([]byte(params.Password), res.Hash) {
err = fmt.Errorf("Error hash validation")
return res, err
}
return res, err
}
type CheckHashParams struct {
Password string
Hash string
}
type CheckHashResult struct {
Match bool `json:"match"`
}
func (tool *Tool) CheckHash(cmd *cobra.Command, args []string) error {
tool.checkHashParams.Password = args[0]
tool.checkHashParams.Hash = args[1]
res, err := tool.checkHash(&tool.checkHashParams)
printResponse(res, err)
return err
}
func (tool *Tool) checkHash(params *CheckHashParams) (*CheckHashResult, error) {
var err error
res := &CheckHashResult{}
if params.Password == "" {
err = fmt.Errorf("Empty password")
return res, err
}
res.Match = passwd.PasswordMatch([]byte(params.Password), params.Hash)
return res, err
}
func printResponse(res any, err error) {
type Response struct {
Error bool `json:"error" json:"error"`
Message string `json:"message,omitempty" json:"message,omitempty"`
Result any `json:"result,omitempty" json:"result,omitempty"`
}
resp := Response{}
if err != nil {
resp.Error = true
resp.Message = err.Error()
} else {
resp.Result = res
}
respBytes, _ := yaml.Marshal(resp)
fmt.Printf("---\n%s\n", string(respBytes))
}

22
cmd/minilbadm/main.go Normal file
View File

@@ -0,0 +1,22 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package main
import (
"os"
)
func main() {
tool := NewTool()
err := tool.Exec(os.Args[1:])
if err != nil {
os.Exit(1)
}
}

44
cmd/minilbadm/tool.go Normal file
View File

@@ -0,0 +1,44 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package main
import (
"os"
"path/filepath"
"helmet/cmd/minilbadm/hash"
"github.com/spf13/cobra"
)
type Tool struct {
cmd *cobra.Command
hashTool *hash.Tool
}
func NewTool() *Tool {
execName := filepath.Base(os.Args[0])
tool := &Tool{}
tool.cmd = &cobra.Command{
Use: execName,
Short: "\nHash tool",
SilenceUsage: true,
}
tool.cmd.CompletionOptions.DisableDefaultCmd = true
tool.hashTool = hash.NewTool()
tool.cmd.AddCommand(tool.hashTool.GetCmd())
return tool
}
func (tool *Tool) Exec(args []string) error {
tool.cmd.SetArgs(args)
return tool.cmd.Execute()
}

View File

@@ -0,0 +1,51 @@
package forwarder
import (
"context"
"time"
"helmet/pkg/client"
"helmet/pkg/mlbctl"
"github.com/spf13/cobra"
)
type CreateForwarderParams struct {
Hostname string
Lport uint32
Dport uint32
Addresses []string
}
type CreateForwarderResult struct{}
func (tool *Tool) CreateForwarder(cmd *cobra.Command, args []string) {
tool.createForwarderParams.Hostname = args[0]
res, err := tool.createForwarder(&tool.createForwarderParams)
printResponse(res, err)
}
func (tool *Tool) createForwarder(params *CreateForwarderParams) (*CreateForwarderResult, error) {
var err error
res := &CreateForwarderResult{}
ref, err := client.NewReferer(params.Hostname)
if err != nil {
return res, err
}
authCred := client.NewAuthCredential(ref.Userinfo())
conn, cli, err := client.NewClient(ref.Hostinfo(), authCred)
if err != nil {
return res, err
}
defer conn.Close()
ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
opReq := &mlbctl.CreateForwarderParams{
Lport: params.Lport,
Dport: params.Dport,
Destinations: params.Addresses,
}
_, err = cli.CreateForwarder(ctx, opReq)
if err != nil {
return res, err
}
return res, err
}

View File

@@ -0,0 +1,47 @@
package forwarder
import (
"context"
"time"
"helmet/pkg/client"
"helmet/pkg/mlbctl"
"github.com/spf13/cobra"
)
type DeleteForwarderParams struct {
Hostname string
Lport uint32
}
type DeleteForwarderResult struct{}
func (tool *Tool) DeleteForwarder(cmd *cobra.Command, args []string) {
tool.deleteForwarderParams.Hostname = args[0]
res, err := tool.deleteForwarder(&tool.deleteForwarderParams)
printResponse(res, err)
}
func (tool *Tool) deleteForwarder(params *DeleteForwarderParams) (*DeleteForwarderResult, error) {
var err error
res := &DeleteForwarderResult{}
ref, err := client.NewReferer(params.Hostname)
if err != nil {
return res, err
}
authCred := client.NewAuthCredential(ref.Userinfo())
conn, cli, err := client.NewClient(ref.Hostinfo(), authCred)
if err != nil {
return res, err
}
defer conn.Close()
ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
opReq := &mlbctl.DeleteForwarderParams{
Lport: params.Lport,
}
_, err = cli.DeleteForwarder(ctx, opReq)
if err != nil {
return res, err
}
return res, err
}

View File

@@ -0,0 +1,78 @@
package forwarder
import (
"fmt"
"github.com/spf13/cobra"
"sigs.k8s.io/yaml"
)
type Tool struct {
cmd *cobra.Command
listForwardersParams ListForwardersParams
createForwarderParams CreateForwarderParams
deleteForwarderParams DeleteForwarderParams
}
func NewTool() *Tool {
tool := &Tool{}
tool.cmd = &cobra.Command{
Use: "forwarder",
Short: "Forwarder operation",
Aliases: []string{"forw"},
}
listForwardersCmd := &cobra.Command{
Use: "list",
Args: cobra.ExactArgs(1),
Short: "List forwarders",
Run: tool.ListForwarders,
}
tool.cmd.AddCommand(listForwardersCmd)
createForwarderCmd := &cobra.Command{
Use: "create",
Args: cobra.ExactArgs(1),
Short: "Create forwarder",
Run: tool.CreateForwarder,
}
createForwarderCmd.Flags().Uint32VarP(&tool.createForwarderParams.Lport, "lport", "L", 0, "Listening port")
createForwarderCmd.Flags().Uint32VarP(&tool.createForwarderParams.Dport, "dport", "D", 0, "Destination port")
createForwarderCmd.Flags().StringArrayVarP(&tool.createForwarderParams.Addresses, "dests", "A", []string{}, "Destination address list")
createForwarderCmd.MarkFlagRequired("lport")
createForwarderCmd.MarkFlagRequired("dport")
createForwarderCmd.MarkFlagRequired("dests")
tool.cmd.AddCommand(createForwarderCmd)
deleteForwarderCmd := &cobra.Command{
Use: "delete",
Args: cobra.ExactArgs(1),
Short: "Delete forwarder",
Run: tool.CreateForwarder,
}
deleteForwarderCmd.Flags().Uint32VarP(&tool.deleteForwarderParams.Lport, "lport", "L", 0, "Listening port")
deleteForwarderCmd.MarkFlagRequired("lport")
tool.cmd.AddCommand(deleteForwarderCmd)
return tool
}
func (tool *Tool) GetCmd() *cobra.Command {
return tool.cmd
}
func printResponse(res any, err error) {
type Response struct {
Error bool `json:"error" json:"error"`
Message string `json:"message,omitempty" json:"message,omitempty"`
Result any `json:"result,omitempty" json:"result,omitempty"`
}
resp := Response{}
if err != nil {
resp.Error = true
resp.Message = err.Error()
} else {
resp.Result = res
}
respBytes, _ := yaml.Marshal(resp)
fmt.Printf("---\n%s\n", string(respBytes))
}

View File

@@ -0,0 +1,47 @@
package forwarder
import (
"context"
"time"
"helmet/pkg/client"
"helmet/pkg/mlbctl"
"github.com/spf13/cobra"
)
type ListForwardersParams struct {
Hostname string
}
type ListForwardersResult struct {
Forwarders []*mlbctl.Forwarder `json:"forwarders,omitempty"`
}
func (tool *Tool) ListForwarders(cmd *cobra.Command, args []string) {
tool.listForwardersParams.Hostname = args[0]
res, err := tool.listForwarders(&tool.listForwardersParams)
printResponse(res, err)
}
func (tool *Tool) listForwarders(params *ListForwardersParams) (*ListForwardersResult, error) {
var err error
res := &ListForwardersResult{}
ref, err := client.NewReferer(params.Hostname)
if err != nil {
return res, err
}
authCred := client.NewAuthCredential(ref.Userinfo())
conn, cli, err := client.NewClient(ref.Hostinfo(), authCred)
if err != nil {
return res, err
}
defer conn.Close()
ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
opReq := &mlbctl.ListForwardersParams{}
opRes, err := cli.ListForwarders(ctx, opReq)
if err != nil {
return res, err
}
res.Forwarders = opRes.Forwarders
return res, err
}

22
cmd/minilbctl/main.go Normal file
View File

@@ -0,0 +1,22 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package main
import (
"os"
)
func main() {
tool := NewTool()
err := tool.Exec(os.Args[1:])
if err != nil {
os.Exit(1)
}
}

View File

@@ -0,0 +1,91 @@
package service
import (
"context"
"fmt"
"time"
"helmet/pkg/client"
"helmet/pkg/mlbctl"
"github.com/spf13/cobra"
"sigs.k8s.io/yaml"
)
type Tool struct {
cmd *cobra.Command
serviceHelloParams ServiceHelloParams
}
func NewTool() *Tool {
tool := &Tool{}
tool.cmd = &cobra.Command{
Use: "service",
Short: "Service operation",
}
serviceHelloCmd := &cobra.Command{
Use: "hello",
Args: cobra.ExactArgs(1),
Short: "Send and receive hello",
Run: tool.ServiceHello,
}
tool.cmd.AddCommand(serviceHelloCmd)
return tool
}
func (tool *Tool) GetCmd() *cobra.Command {
return tool.cmd
}
type ServiceHelloParams struct {
Hostname string
}
type ServiceHelloResult struct {
Message string `json:"message,omitempty"`
}
func (tool *Tool) ServiceHello(cmd *cobra.Command, args []string) {
tool.serviceHelloParams.Hostname = args[0]
res, err := tool.serviceHello(&tool.serviceHelloParams)
printResponse(res, err)
}
func (tool *Tool) serviceHello(params *ServiceHelloParams) (*ServiceHelloResult, error) {
var err error
res := &ServiceHelloResult{}
ref, err := client.NewReferer(params.Hostname)
if err != nil {
return res, err
}
authCred := client.NewAuthCredential(ref.Userinfo())
conn, cli, err := client.NewClient(ref.Hostinfo(), authCred)
if err != nil {
return res, err
}
defer conn.Close()
ctx, _ := context.WithTimeout(context.Background(), 1*time.Second)
opReq := &mlbctl.GetHelloParams{}
opRes, err := cli.GetHello(ctx, opReq)
if err != nil {
return res, err
}
res.Message = opRes.Message
return res, err
}
func printResponse(res any, err error) {
type Response struct {
Error bool `json:"error" json:"error"`
Message string `json:"message,omitempty" json:"message,omitempty"`
Result any `json:"result,omitempty" json:"result,omitempty"`
}
resp := Response{}
if err != nil {
resp.Error = true
resp.Message = err.Error()
} else {
resp.Result = res
}
respBytes, _ := yaml.Marshal(resp)
fmt.Printf("---\n%s\n", string(respBytes))
}

49
cmd/minilbctl/tool.go Normal file
View File

@@ -0,0 +1,49 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package main
import (
"os"
"path/filepath"
"helmet/cmd/minilbctl/forwarder"
"helmet/cmd/minilbctl/service"
"github.com/spf13/cobra"
)
type Tool struct {
cmd *cobra.Command
forwarderTool *forwarder.Tool
serviceTool *service.Tool
}
func NewTool() *Tool {
execName := filepath.Base(os.Args[0])
tool := &Tool{}
tool.cmd = &cobra.Command{
Use: execName,
Short: "\nService tools",
SilenceUsage: true,
}
tool.cmd.CompletionOptions.DisableDefaultCmd = true
tool.serviceTool = service.NewTool()
tool.cmd.AddCommand(tool.serviceTool.GetCmd())
tool.forwarderTool = forwarder.NewTool()
tool.cmd.AddCommand(tool.forwarderTool.GetCmd())
return tool
}
func (tool *Tool) Exec(args []string) error {
tool.cmd.SetArgs(args)
return tool.cmd.Execute()
}

28
cmd/minilbd/main.go Normal file
View File

@@ -0,0 +1,28 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package main
import (
"os"
"helmet/app/logger"
"helmet/cmd/minilbd/starter"
)
func main() {
log := logger.NewLogger("main")
sta := starter.NewStarter()
err := sta.Exec()
if err != nil {
log.Errorf("%v", err)
os.Exit(1)
}
os.Exit(0)
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package starter
import (
"os"
"path/filepath"
"helmet/app/server"
"helmet/pkg/client"
"github.com/spf13/cobra"
)
type Starter struct {
runAsDaemon bool
port uint32
cmd *cobra.Command
srv *server.Server
}
func NewStarter() *Starter {
execName := filepath.Base(os.Args[0])
sta := &Starter{}
cmd := &cobra.Command{
Use: execName,
Short: "\nProxy service",
SilenceUsage: true,
RunE: sta.run,
}
cmd.CompletionOptions.DisableDefaultCmd = true
cmd.Flags().BoolVarP(&sta.runAsDaemon, "asDaemon", "D", false, "Run service as daemon")
cmd.Flags().Uint32VarP(&sta.port, "port", "P", client.DefaultServicePort, "Service port")
sta.cmd = cmd
return sta
}
func (sta *Starter) GetCmd() *cobra.Command {
return sta.cmd
}
func (sta *Starter) run(cmd *cobra.Command, args []string) error {
var err error
srv, err := server.NewServer()
if err != nil {
return err
}
err = srv.Configure()
if err != nil {
return err
}
srv.Config().AsDaemon = sta.runAsDaemon
srv.Config().Service.Port = sta.port
err = srv.Daemonize()
if err != nil {
return err
}
err = srv.Build()
if err != nil {
return err
}
err = srv.Run()
if err != nil {
return err
}
sta.srv = srv
return err
}
func (sta *Starter) Exec() error {
return sta.cmd.Execute()
}

119
configure vendored
View File

@@ -608,6 +608,8 @@ PACKAGE_URL=''
ac_default_prefix=/usr/local ac_default_prefix=/usr/local
ac_subst_vars='LTLIBOBJS ac_subst_vars='LTLIBOBJS
LIBOBJS LIBOBJS
srv_bindir
srv_sbindir
srv_datadir srv_datadir
srv_libdir srv_libdir
srv_sharedir srv_sharedir
@@ -615,6 +617,8 @@ srv_rundir
srv_logdir srv_logdir
srv_confdir srv_confdir
srv_devel_mode srv_devel_mode
run_user
RUN_USER
SYSTEMD_FALSE SYSTEMD_FALSE
SYSTEMD_TRUE SYSTEMD_TRUE
LINUX_OS_FALSE LINUX_OS_FALSE
@@ -635,6 +639,7 @@ DPKGSOURCE
DBUILDPACKAGE DBUILDPACKAGE
HELM HELM
PODMAN PODMAN
PROTOC
BASENAME BASENAME
CPIO CPIO
SUDO SUDO
@@ -719,6 +724,7 @@ ac_subst_files=''
ac_user_opts=' ac_user_opts='
enable_option_checking enable_option_checking
enable_silent_rules enable_silent_rules
with_user
enable_devel_mode enable_devel_mode
with_confdir with_confdir
with_logdir with_logdir
@@ -1364,6 +1370,7 @@ Optional Features:
Optional Packages: Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--with-user=${PACKAGE} set executing user name
--with-confdir=PATH set configuration dir to PATH (default: --with-confdir=PATH set configuration dir to PATH (default:
$SRV_CONFDIR) $SRV_CONFDIR)
--with-logdir=PATH set path for logdir (default: $SRV_LOGDIR) --with-logdir=PATH set path for logdir (default: $SRV_LOGDIR)
@@ -3200,6 +3207,57 @@ fi
done done
for ac_prog in protoc true
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
printf %s "checking for $ac_word... " >&6; }
if test ${ac_cv_path_PROTOC+y}
then :
printf %s "(cached) " >&6
else case e in #(
e) case $PROTOC in
[\\/]* | ?:[\\/]*)
ac_cv_path_PROTOC="$PROTOC" # Let the user override the test with a path.
;;
*)
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
case $as_dir in #(((
'') as_dir=./ ;;
*/) ;;
*) as_dir=$as_dir/ ;;
esac
for ac_exec_ext in '' $ac_executable_extensions; do
if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_path_PROTOC="$as_dir$ac_word$ac_exec_ext"
printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
done
IFS=$as_save_IFS
;;
esac ;;
esac
fi
PROTOC=$ac_cv_path_PROTOC
if test -n "$PROTOC"; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PROTOC" >&5
printf "%s\n" "$PROTOC" >&6; }
else
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
fi
test -n "$PROTOC" && break
done
for ac_prog in podman true for ac_prog in podman true
do do
# Extract the first word of "$ac_prog", so it can be a program name with args. # Extract the first word of "$ac_prog", so it can be a program name with args.
@@ -3611,6 +3669,59 @@ test "x$prefix" == "xNONE" && prefix=$ac_default_prefix
test "x$libexecdir" == "xNONE" && libexecdir=${prefix}/lib test "x$libexecdir" == "xNONE" && libexecdir=${prefix}/lib
case $host_os in
*freebsd* )
default_user="daemon"
default_group="daemon"
;;
*linux* )
default_user="daemon"
default_group="daemon"
;;
esac
# Check whether --with-user was given.
if test ${with_user+y}
then :
withval=$with_user; if test ! -z "$with_user" ; then
case $with_user in
"")
as_fn_error $? "You must specify user name" "$LINENO" 5
;;
*)
RUN_USER="$with_user"
;;
esac
else
RUN_USER="$default_user"
fi
else case e in #(
e) RUN_USER="$default_user" ;;
esac
fi
if test "x$enable_devel_mode" = "xyes"
then :
RUN_USER="`id -un`"
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: run_user set as ${RUN_USER}" >&5
printf "%s\n" "$as_me: run_user set as ${RUN_USER}" >&6;}
printf "%s\n" "#define RUN_USER \"$RUN_USER\"" >>confdefs.h
RUN_USER="$RUN_USER"
printf "%s\n" "#define run_user \"$RUN_USER\"" >>confdefs.h
run_user="$RUN_USER"
# Check whether --enable-devel-mode was given. # Check whether --enable-devel-mode was given.
if test ${enable_devel_mode+y} if test ${enable_devel_mode+y}
@@ -3654,7 +3765,6 @@ then :
fi fi
if test "x$enable_devel_mode" = "xyes" if test "x$enable_devel_mode" = "xyes"
then : then :
@@ -3862,9 +3972,13 @@ srv_datadir="$SRV_DATADIR"
printf "%s\n" "$as_me: srv_datadir set as ${SRV_DATADIR}" >&6;} printf "%s\n" "$as_me: srv_datadir set as ${SRV_DATADIR}" >&6;}
srv_sbindir="${prefix}/sbin"
srv_bindir="${prefix}/bin"
ac_config_files="$ac_config_files Makefile app/config/variant.go initrc/minilbd.service debian/control debian/changelog"
ac_config_files="$ac_config_files Makefile app/config/variant.go initrc/minilbd.service initrc/minilbd debian/control debian/changelog"
cat >confcache <<\_ACEOF cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure # This file is a shell script that caches the results of configure
@@ -4618,6 +4732,7 @@ do
"Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
"app/config/variant.go") CONFIG_FILES="$CONFIG_FILES app/config/variant.go" ;; "app/config/variant.go") CONFIG_FILES="$CONFIG_FILES app/config/variant.go" ;;
"initrc/minilbd.service") CONFIG_FILES="$CONFIG_FILES initrc/minilbd.service" ;; "initrc/minilbd.service") CONFIG_FILES="$CONFIG_FILES initrc/minilbd.service" ;;
"initrc/minilbd") CONFIG_FILES="$CONFIG_FILES initrc/minilbd" ;;
"debian/control") CONFIG_FILES="$CONFIG_FILES debian/control" ;; "debian/control") CONFIG_FILES="$CONFIG_FILES debian/control" ;;
"debian/changelog") CONFIG_FILES="$CONFIG_FILES debian/changelog" ;; "debian/changelog") CONFIG_FILES="$CONFIG_FILES debian/changelog" ;;

View File

@@ -18,6 +18,7 @@ AC_PATH_PROGS([SUDO],[sudo false])
AC_PATH_PROGS([CPIO],[cpio false]) AC_PATH_PROGS([CPIO],[cpio false])
AC_PATH_PROGS([BASENAME],[basename]) AC_PATH_PROGS([BASENAME],[basename])
AC_PATH_PROGS([PROTOC],[protoc true])
AC_PATH_PROGS([PODMAN],[podman true]) AC_PATH_PROGS([PODMAN],[podman true])
AC_PATH_PROGS([HELM],[helm true]) AC_PATH_PROGS([HELM],[helm true])
AC_PATH_PROGS([DBUILDPACKAGE],[dpkg-buildpackage true]) AC_PATH_PROGS([DBUILDPACKAGE],[dpkg-buildpackage true])
@@ -58,6 +59,44 @@ fi
test "x$prefix" == "xNONE" && prefix=$ac_default_prefix test "x$prefix" == "xNONE" && prefix=$ac_default_prefix
test "x$libexecdir" == "xNONE" && libexecdir=${prefix}/lib test "x$libexecdir" == "xNONE" && libexecdir=${prefix}/lib
dnl --------------------------------------------------------------------------------------
case $host_os in
*freebsd* )
default_user="daemon"
default_group="daemon"
;;
*linux* )
default_user="daemon"
default_group="daemon"
;;
esac
AC_ARG_WITH(user,
AS_HELP_STRING([--with-user=${PACKAGE}],[set executing user name]),
[ if test ! -z "$with_user" ; then
case $with_user in
"")
AC_MSG_ERROR(You must specify user name)
;;
*)
RUN_USER="$with_user"
;;
esac
else
RUN_USER="$default_user"
fi ],
[ RUN_USER="$default_user" ])
AS_IF([test "x$enable_devel_mode" = "xyes"], [
RUN_USER="`id -un`"
])
AC_MSG_NOTICE(run_user set as ${RUN_USER})
AC_DEFINE_UNQUOTED(RUN_USER, "$RUN_USER", [effective user])
AC_SUBST(RUN_USER, "$RUN_USER")
AC_DEFINE_UNQUOTED(run_user, "$RUN_USER", [effective user])
AC_SUBST(run_user, "$RUN_USER")
dnl -------------------------------------------------------------------------------------- dnl --------------------------------------------------------------------------------------
@@ -90,7 +129,6 @@ AC_ARG_WITH(confdir,
esac esac
fi ]) fi ])
AS_IF([test "x$enable_devel_mode" = "xyes"], [ AS_IF([test "x$enable_devel_mode" = "xyes"], [
SRV_CONFDIR="${SRCDIR}/etc/${PACKAGE}" SRV_CONFDIR="${SRCDIR}/etc/${PACKAGE}"
sysconfdir="${SRCDIR}/etc/${PACKAGE}" sysconfdir="${SRCDIR}/etc/${PACKAGE}"
@@ -239,12 +277,15 @@ AC_MSG_NOTICE(srv_datadir set as ${SRV_DATADIR})
dnl -------------------------------------------------------------------------------------- dnl --------------------------------------------------------------------------------------
AC_SUBST(srv_sbindir, "${prefix}/sbin")
AC_SUBST(srv_bindir, "${prefix}/bin")
AC_CONFIG_FILES([ AC_CONFIG_FILES([
Makefile Makefile
app/config/variant.go app/config/variant.go
initrc/minilbd.service initrc/minilbd.service
initrc/minilbd
debian/control debian/control
debian/changelog debian/changelog
]) ])

24
initrc/minilbd.in Normal file
View File

@@ -0,0 +1,24 @@
#!/bin/sh
#
# $Id$
#
# PROVIDE: minilbd
# REQUIRE: DAEMON
. /etc/rc.subr
name="minilbd"
rcvar="minilbd_enable"
pidfile="@srv_rundir@/minilbd.pid"
command="@prefix@/sbin/${name}"
command_args="--asDaemon=true"
procname="@prefix@/sbin/${name}"
load_rc_config ${name}
: ${minilbd_enable:="NO"}
run_rc_command "$1"
#EOF

View File

@@ -3,10 +3,10 @@ Description=minilbd
[Service] [Service]
Type=forking Type=forking
ExecStart=@srv_sbindir@/minilbd -asDaemon=true ExecStart=/usr/sbin/minilbd --asDaemon=true
ExecReload=/bin/kill -HUP $MAINPID ExecReload=/bin/kill -HUP $MAINPID
ExecRestart=/bin/kill -HUP $MAINPID ExecRestart=/bin/kill -HUP $MAINPID
ExecStartPre=/usr/bin/install -d -o root -g root /home/ziggi/Projects/gserver/tmp/run /home/ziggi/Projects/gserver/tmp/log ExecStartPre=/usr/bin/install -d -o daemon /var/run/minilb /var/log/minilb
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View File

@@ -3,10 +3,10 @@ Description=minilbd
[Service] [Service]
Type=forking Type=forking
ExecStart=@srv_sbindir@/minilbd -asDaemon=true ExecStart=@srv_sbindir@/minilbd --asDaemon=true
ExecReload=/bin/kill -HUP $MAINPID ExecReload=/bin/kill -HUP $MAINPID
ExecRestart=/bin/kill -HUP $MAINPID ExecRestart=/bin/kill -HUP $MAINPID
ExecStartPre=/usr/bin/install -d -o root -g root @srv_rundir@ @srv_logdir@ ExecStartPre=/usr/bin/install -d -o @run_user@ @srv_rundir@ @srv_logdir@
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

236
missing
View File

@@ -1,236 +0,0 @@
#! /bin/sh
# Common wrapper for a few potentially missing GNU and other programs.
scriptversion=2024-06-07.14; # UTC
# shellcheck disable=SC2006,SC2268 # we must support pre-POSIX shells
# Copyright (C) 1996-2024 Free Software Foundation, Inc.
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try '$0 --help' for more information"
exit 1
fi
case $1 in
--is-lightweight)
# Used by our autoconf macros to check whether the available missing
# script is modern enough.
exit 0
;;
--run)
# Back-compat with the calling convention used by older automake.
shift
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
to PROGRAM being missing or too old.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
Supported PROGRAM values:
aclocal autoconf autogen autoheader autom4te automake autoreconf
bison flex help2man lex makeinfo perl yacc
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
'g' are ignored when checking the name.
Report bugs to <bug-automake@gnu.org>.
GNU Automake home page: <https://www.gnu.org/software/automake/>.
General help using GNU software: <https://www.gnu.org/gethelp/>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing (GNU Automake) $scriptversion"
exit $?
;;
-*)
echo 1>&2 "$0: unknown '$1' option"
echo 1>&2 "Try '$0 --help' for more information"
exit 1
;;
esac
# Run the given program, remember its exit status.
"$@"; st=$?
# If it succeeded, we are done.
test $st -eq 0 && exit 0
# Also exit now if we it failed (or wasn't found), and '--version' was
# passed; such an option is passed most likely to detect whether the
# program is present and works.
case $2 in --version|--help) exit $st;; esac
# Exit code 63 means version mismatch. This often happens when the user
# tries to use an ancient version of a tool on a file that requires a
# minimum version.
if test $st -eq 63; then
msg="probably too old"
elif test $st -eq 127; then
# Program was missing.
msg="missing on your system"
else
# Program was found and executed, but failed. Give up.
exit $st
fi
perl_URL=https://www.perl.org/
flex_URL=https://github.com/westes/flex
gnu_software_URL=https://www.gnu.org/software
program_details ()
{
case $1 in
aclocal|automake|autoreconf)
echo "The '$1' program is part of the GNU Automake package:"
echo "<$gnu_software_URL/automake>"
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/autoconf>"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
autoconf|autom4te|autoheader)
echo "The '$1' program is part of the GNU Autoconf package:"
echo "<$gnu_software_URL/autoconf/>"
echo "It also requires GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
*)
:
;;
esac
}
give_advice ()
{
# Normalize program name to check for.
normalized_program=`echo "$1" | sed '
s/^gnu-//; t
s/^gnu//; t
s/^g//; t'`
printf '%s\n' "'$1' is $msg."
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
autoheader_deps="'acconfig.h'"
automake_deps="'Makefile.am'"
aclocal_deps="'acinclude.m4'"
case $normalized_program in
aclocal*)
echo "You should only need it if you modified $aclocal_deps or"
echo "$configure_deps."
;;
autoconf*)
echo "You should only need it if you modified $configure_deps."
;;
autogen*)
echo "You should only need it if you modified a '.def' or '.tpl' file."
echo "You may want to install the GNU AutoGen package:"
echo "<$gnu_software_URL/autogen/>"
;;
autoheader*)
echo "You should only need it if you modified $autoheader_deps or"
echo "$configure_deps."
;;
automake*)
echo "You should only need it if you modified $automake_deps or"
echo "$configure_deps."
;;
autom4te*)
echo "You might have modified some maintainer files that require"
echo "the 'autom4te' program to be rebuilt."
;;
autoreconf*)
echo "You should only need it if you modified $aclocal_deps or"
echo "$automake_deps or $autoheader_deps or $automake_deps or"
echo "$configure_deps."
;;
bison*|yacc*)
echo "You should only need it if you modified a '.y' file."
echo "You may want to install the GNU Bison package:"
echo "<$gnu_software_URL/bison/>"
;;
help2man*)
echo "You should only need it if you modified a dependency" \
"of a man page."
echo "You may want to install the GNU Help2man package:"
echo "<$gnu_software_URL/help2man/>"
;;
lex*|flex*)
echo "You should only need it if you modified a '.l' file."
echo "You may want to install the Fast Lexical Analyzer package:"
echo "<$flex_URL>"
;;
makeinfo*)
echo "You should only need it if you modified a '.texi' file, or"
echo "any other file indirectly affecting the aspect of the manual."
echo "You might want to install the Texinfo package:"
echo "<$gnu_software_URL/texinfo/>"
echo "The spurious makeinfo call might also be the consequence of"
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
echo "want to install GNU make:"
echo "<$gnu_software_URL/make/>"
;;
perl*)
echo "You should only need it to run GNU Autoconf, GNU Automake, "
echo " assorted other tools, or if you modified a Perl source file."
echo "You may want to install the Perl 5 language interpreter:"
echo "<$perl_URL>"
;;
*)
echo "You might have modified some files without having the proper"
echo "tools for further handling them. Check the 'README' file, it"
echo "often tells you about the needed prerequisites for installing"
echo "this package. You may also peek at any GNU archive site, in"
echo "case some other package contains this missing '$1' program."
;;
esac
program_details "$normalized_program"
}
give_advice "$1" | sed -e '1s/^/WARNING: /' \
-e '2,$s/^/ /' >&2
# Propagate the correct exit status (expected to be 127 for a program
# not found, 63 for a program that failed due to version mismatch).
exit $st
# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:

View File

@@ -101,6 +101,366 @@ func (x *GetHelloResult) GetMessage() string {
return "" return ""
} }
type Forwarder struct {
state protoimpl.MessageState `protogen:"open.v1"`
Lport uint32 `protobuf:"varint,1,opt,name=lport,proto3" json:"lport,omitempty"`
Dport uint32 `protobuf:"varint,2,opt,name=dport,proto3" json:"dport,omitempty"`
Destinations []*Destination `protobuf:"bytes,3,rep,name=destinations,proto3" json:"destinations,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Forwarder) Reset() {
*x = Forwarder{}
mi := &file_mlbctl_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Forwarder) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Forwarder) ProtoMessage() {}
func (x *Forwarder) ProtoReflect() protoreflect.Message {
mi := &file_mlbctl_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Forwarder.ProtoReflect.Descriptor instead.
func (*Forwarder) Descriptor() ([]byte, []int) {
return file_mlbctl_proto_rawDescGZIP(), []int{2}
}
func (x *Forwarder) GetLport() uint32 {
if x != nil {
return x.Lport
}
return 0
}
func (x *Forwarder) GetDport() uint32 {
if x != nil {
return x.Dport
}
return 0
}
func (x *Forwarder) GetDestinations() []*Destination {
if x != nil {
return x.Destinations
}
return nil
}
type Destination struct {
state protoimpl.MessageState `protogen:"open.v1"`
Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Destination) Reset() {
*x = Destination{}
mi := &file_mlbctl_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Destination) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Destination) ProtoMessage() {}
func (x *Destination) ProtoReflect() protoreflect.Message {
mi := &file_mlbctl_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Destination.ProtoReflect.Descriptor instead.
func (*Destination) Descriptor() ([]byte, []int) {
return file_mlbctl_proto_rawDescGZIP(), []int{3}
}
func (x *Destination) GetAddress() string {
if x != nil {
return x.Address
}
return ""
}
type ListForwardersParams struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListForwardersParams) Reset() {
*x = ListForwardersParams{}
mi := &file_mlbctl_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListForwardersParams) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListForwardersParams) ProtoMessage() {}
func (x *ListForwardersParams) ProtoReflect() protoreflect.Message {
mi := &file_mlbctl_proto_msgTypes[4]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListForwardersParams.ProtoReflect.Descriptor instead.
func (*ListForwardersParams) Descriptor() ([]byte, []int) {
return file_mlbctl_proto_rawDescGZIP(), []int{4}
}
type ListForwardersResult struct {
state protoimpl.MessageState `protogen:"open.v1"`
Forwarders []*Forwarder `protobuf:"bytes,1,rep,name=forwarders,proto3" json:"forwarders,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ListForwardersResult) Reset() {
*x = ListForwardersResult{}
mi := &file_mlbctl_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ListForwardersResult) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListForwardersResult) ProtoMessage() {}
func (x *ListForwardersResult) ProtoReflect() protoreflect.Message {
mi := &file_mlbctl_proto_msgTypes[5]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListForwardersResult.ProtoReflect.Descriptor instead.
func (*ListForwardersResult) Descriptor() ([]byte, []int) {
return file_mlbctl_proto_rawDescGZIP(), []int{5}
}
func (x *ListForwardersResult) GetForwarders() []*Forwarder {
if x != nil {
return x.Forwarders
}
return nil
}
type CreateForwarderParams struct {
state protoimpl.MessageState `protogen:"open.v1"`
Lport uint32 `protobuf:"varint,1,opt,name=lport,proto3" json:"lport,omitempty"`
Dport uint32 `protobuf:"varint,2,opt,name=dport,proto3" json:"dport,omitempty"`
Destinations []string `protobuf:"bytes,3,rep,name=destinations,proto3" json:"destinations,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CreateForwarderParams) Reset() {
*x = CreateForwarderParams{}
mi := &file_mlbctl_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CreateForwarderParams) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CreateForwarderParams) ProtoMessage() {}
func (x *CreateForwarderParams) ProtoReflect() protoreflect.Message {
mi := &file_mlbctl_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CreateForwarderParams.ProtoReflect.Descriptor instead.
func (*CreateForwarderParams) Descriptor() ([]byte, []int) {
return file_mlbctl_proto_rawDescGZIP(), []int{6}
}
func (x *CreateForwarderParams) GetLport() uint32 {
if x != nil {
return x.Lport
}
return 0
}
func (x *CreateForwarderParams) GetDport() uint32 {
if x != nil {
return x.Dport
}
return 0
}
func (x *CreateForwarderParams) GetDestinations() []string {
if x != nil {
return x.Destinations
}
return nil
}
type CreateForwarderResult struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CreateForwarderResult) Reset() {
*x = CreateForwarderResult{}
mi := &file_mlbctl_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CreateForwarderResult) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CreateForwarderResult) ProtoMessage() {}
func (x *CreateForwarderResult) ProtoReflect() protoreflect.Message {
mi := &file_mlbctl_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CreateForwarderResult.ProtoReflect.Descriptor instead.
func (*CreateForwarderResult) Descriptor() ([]byte, []int) {
return file_mlbctl_proto_rawDescGZIP(), []int{7}
}
type DeleteForwarderParams struct {
state protoimpl.MessageState `protogen:"open.v1"`
Lport uint32 `protobuf:"varint,1,opt,name=lport,proto3" json:"lport,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DeleteForwarderParams) Reset() {
*x = DeleteForwarderParams{}
mi := &file_mlbctl_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DeleteForwarderParams) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteForwarderParams) ProtoMessage() {}
func (x *DeleteForwarderParams) ProtoReflect() protoreflect.Message {
mi := &file_mlbctl_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteForwarderParams.ProtoReflect.Descriptor instead.
func (*DeleteForwarderParams) Descriptor() ([]byte, []int) {
return file_mlbctl_proto_rawDescGZIP(), []int{8}
}
func (x *DeleteForwarderParams) GetLport() uint32 {
if x != nil {
return x.Lport
}
return 0
}
type DeleteForwarderResult struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *DeleteForwarderResult) Reset() {
*x = DeleteForwarderResult{}
mi := &file_mlbctl_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *DeleteForwarderResult) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteForwarderResult) ProtoMessage() {}
func (x *DeleteForwarderResult) ProtoReflect() protoreflect.Message {
mi := &file_mlbctl_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteForwarderResult.ProtoReflect.Descriptor instead.
func (*DeleteForwarderResult) Descriptor() ([]byte, []int) {
return file_mlbctl_proto_rawDescGZIP(), []int{9}
}
var File_mlbctl_proto protoreflect.FileDescriptor var File_mlbctl_proto protoreflect.FileDescriptor
var file_mlbctl_proto_rawDesc = string([]byte{ var file_mlbctl_proto_rawDesc = string([]byte{
@@ -109,13 +469,56 @@ var file_mlbctl_proto_rawDesc = string([]byte{
0x6c, 0x6f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x2a, 0x0a, 0x0e, 0x67, 0x65, 0x74, 0x48, 0x6c, 0x6f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x2a, 0x0a, 0x0e, 0x67, 0x65, 0x74, 0x48,
0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x32, 0x47, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x73, 0x61, 0x67, 0x65, 0x22, 0x70, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65,
0x3c, 0x0a, 0x08, 0x67, 0x65, 0x74, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x12, 0x16, 0x2e, 0x6d, 0x6c, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
0x62, 0x63, 0x74, 0x6c, 0x2e, 0x67, 0x65, 0x74, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x50, 0x61, 0x72, 0x52, 0x05, 0x6c, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x70, 0x6f, 0x72, 0x74,
0x61, 0x6d, 0x73, 0x1a, 0x16, 0x2e, 0x6d, 0x6c, 0x62, 0x63, 0x74, 0x6c, 0x2e, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x64, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x37, 0x0a,
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x42, 0x0a, 0x5a, 0x0c, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20,
0x08, 0x2e, 0x3b, 0x6d, 0x6c, 0x62, 0x63, 0x74, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6d, 0x6c, 0x62, 0x63, 0x74, 0x6c, 0x2e, 0x64, 0x65, 0x73,
0x33, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x27, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22,
0x16, 0x0a, 0x14, 0x6c, 0x69, 0x73, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72,
0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x49, 0x0a, 0x14, 0x6c, 0x69, 0x73, 0x74, 0x46,
0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12,
0x31, 0x0a, 0x0a, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6d, 0x6c, 0x62, 0x63, 0x74, 0x6c, 0x2e, 0x66, 0x6f, 0x72,
0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x52, 0x0a, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65,
0x72, 0x73, 0x22, 0x67, 0x0a, 0x15, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x77,
0x61, 0x72, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6c,
0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x70, 0x6f, 0x72,
0x74, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x05, 0x64, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x65, 0x73, 0x74, 0x69,
0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x64,
0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x17, 0x0a, 0x15, 0x63,
0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65,
0x73, 0x75, 0x6c, 0x74, 0x22, 0x2d, 0x0a, 0x15, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f,
0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x14, 0x0a,
0x05, 0x6c, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x70,
0x6f, 0x72, 0x74, 0x22, 0x17, 0x0a, 0x15, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72,
0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x32, 0xbd, 0x02, 0x0a,
0x07, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x3c, 0x0a, 0x08, 0x67, 0x65, 0x74, 0x48,
0x65, 0x6c, 0x6c, 0x6f, 0x12, 0x16, 0x2e, 0x6d, 0x6c, 0x62, 0x63, 0x74, 0x6c, 0x2e, 0x67, 0x65,
0x74, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x16, 0x2e, 0x6d,
0x6c, 0x62, 0x63, 0x74, 0x6c, 0x2e, 0x67, 0x65, 0x74, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x52, 0x65,
0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1d, 0x2e, 0x6d, 0x6c, 0x62, 0x63,
0x74, 0x6c, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64,
0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1d, 0x2e, 0x6d, 0x6c, 0x62, 0x63, 0x74,
0x6c, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65,
0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x0e, 0x6c, 0x69, 0x73,
0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x73, 0x12, 0x1c, 0x2e, 0x6d, 0x6c,
0x62, 0x63, 0x74, 0x6c, 0x2e, 0x6c, 0x69, 0x73, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64,
0x65, 0x72, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1c, 0x2e, 0x6d, 0x6c, 0x62, 0x63,
0x74, 0x6c, 0x2e, 0x6c, 0x69, 0x73, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72,
0x73, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0f, 0x64, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x12, 0x1d, 0x2e, 0x6d,
0x6c, 0x62, 0x63, 0x74, 0x6c, 0x2e, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x77,
0x61, 0x72, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1d, 0x2e, 0x6d, 0x6c,
0x62, 0x63, 0x74, 0x6c, 0x2e, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x77, 0x61,
0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x00, 0x42, 0x0a, 0x5a, 0x08,
0x2e, 0x3b, 0x6d, 0x6c, 0x62, 0x63, 0x74, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}) })
var ( var (
@@ -130,19 +533,35 @@ func file_mlbctl_proto_rawDescGZIP() []byte {
return file_mlbctl_proto_rawDescData return file_mlbctl_proto_rawDescData
} }
var file_mlbctl_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_mlbctl_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_mlbctl_proto_goTypes = []any{ var file_mlbctl_proto_goTypes = []any{
(*GetHelloParams)(nil), // 0: mlbctl.getHelloParams (*GetHelloParams)(nil), // 0: mlbctl.getHelloParams
(*GetHelloResult)(nil), // 1: mlbctl.getHelloResult (*GetHelloResult)(nil), // 1: mlbctl.getHelloResult
(*Forwarder)(nil), // 2: mlbctl.forwarder
(*Destination)(nil), // 3: mlbctl.destination
(*ListForwardersParams)(nil), // 4: mlbctl.listForwardersParams
(*ListForwardersResult)(nil), // 5: mlbctl.listForwardersResult
(*CreateForwarderParams)(nil), // 6: mlbctl.createForwarderParams
(*CreateForwarderResult)(nil), // 7: mlbctl.createForwarderResult
(*DeleteForwarderParams)(nil), // 8: mlbctl.deleteForwarderParams
(*DeleteForwarderResult)(nil), // 9: mlbctl.deleteForwarderResult
} }
var file_mlbctl_proto_depIdxs = []int32{ var file_mlbctl_proto_depIdxs = []int32{
0, // 0: mlbctl.Control.getHello:input_type -> mlbctl.getHelloParams 3, // 0: mlbctl.forwarder.destinations:type_name -> mlbctl.destination
1, // 1: mlbctl.Control.getHello:output_type -> mlbctl.getHelloResult 2, // 1: mlbctl.listForwardersResult.forwarders:type_name -> mlbctl.forwarder
1, // [1:2] is the sub-list for method output_type 0, // 2: mlbctl.Control.getHello:input_type -> mlbctl.getHelloParams
0, // [0:1] is the sub-list for method input_type 6, // 3: mlbctl.Control.createForwarder:input_type -> mlbctl.createForwarderParams
0, // [0:0] is the sub-list for extension type_name 4, // 4: mlbctl.Control.listForwarders:input_type -> mlbctl.listForwardersParams
0, // [0:0] is the sub-list for extension extendee 8, // 5: mlbctl.Control.deleteForwarder:input_type -> mlbctl.deleteForwarderParams
0, // [0:0] is the sub-list for field type_name 1, // 6: mlbctl.Control.getHello:output_type -> mlbctl.getHelloResult
7, // 7: mlbctl.Control.createForwarder:output_type -> mlbctl.createForwarderResult
5, // 8: mlbctl.Control.listForwarders:output_type -> mlbctl.listForwardersResult
9, // 9: mlbctl.Control.deleteForwarder:output_type -> mlbctl.deleteForwarderResult
6, // [6:10] is the sub-list for method output_type
2, // [2:6] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
} }
func init() { file_mlbctl_proto_init() } func init() { file_mlbctl_proto_init() }
@@ -156,7 +575,7 @@ func file_mlbctl_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_mlbctl_proto_rawDesc), len(file_mlbctl_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_mlbctl_proto_rawDesc), len(file_mlbctl_proto_rawDesc)),
NumEnums: 0, NumEnums: 0,
NumMessages: 2, NumMessages: 10,
NumExtensions: 0, NumExtensions: 0,
NumServices: 1, NumServices: 1,
}, },

View File

@@ -19,7 +19,10 @@ import (
const _ = grpc.SupportPackageIsVersion8 const _ = grpc.SupportPackageIsVersion8
const ( const (
Control_GetHello_FullMethodName = "/mlbctl.Control/getHello" Control_GetHello_FullMethodName = "/mlbctl.Control/getHello"
Control_CreateForwarder_FullMethodName = "/mlbctl.Control/createForwarder"
Control_ListForwarders_FullMethodName = "/mlbctl.Control/listForwarders"
Control_DeleteForwarder_FullMethodName = "/mlbctl.Control/deleteForwarder"
) )
// ControlClient is the client API for Control service. // ControlClient is the client API for Control service.
@@ -27,6 +30,9 @@ const (
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type ControlClient interface { type ControlClient interface {
GetHello(ctx context.Context, in *GetHelloParams, opts ...grpc.CallOption) (*GetHelloResult, error) GetHello(ctx context.Context, in *GetHelloParams, opts ...grpc.CallOption) (*GetHelloResult, error)
CreateForwarder(ctx context.Context, in *CreateForwarderParams, opts ...grpc.CallOption) (*CreateForwarderResult, error)
ListForwarders(ctx context.Context, in *ListForwardersParams, opts ...grpc.CallOption) (*ListForwardersResult, error)
DeleteForwarder(ctx context.Context, in *DeleteForwarderParams, opts ...grpc.CallOption) (*DeleteForwarderResult, error)
} }
type controlClient struct { type controlClient struct {
@@ -47,11 +53,44 @@ func (c *controlClient) GetHello(ctx context.Context, in *GetHelloParams, opts .
return out, nil return out, nil
} }
func (c *controlClient) CreateForwarder(ctx context.Context, in *CreateForwarderParams, opts ...grpc.CallOption) (*CreateForwarderResult, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(CreateForwarderResult)
err := c.cc.Invoke(ctx, Control_CreateForwarder_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *controlClient) ListForwarders(ctx context.Context, in *ListForwardersParams, opts ...grpc.CallOption) (*ListForwardersResult, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ListForwardersResult)
err := c.cc.Invoke(ctx, Control_ListForwarders_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *controlClient) DeleteForwarder(ctx context.Context, in *DeleteForwarderParams, opts ...grpc.CallOption) (*DeleteForwarderResult, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(DeleteForwarderResult)
err := c.cc.Invoke(ctx, Control_DeleteForwarder_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// ControlServer is the server API for Control service. // ControlServer is the server API for Control service.
// All implementations must embed UnimplementedControlServer // All implementations must embed UnimplementedControlServer
// for forward compatibility // for forward compatibility
type ControlServer interface { type ControlServer interface {
GetHello(context.Context, *GetHelloParams) (*GetHelloResult, error) GetHello(context.Context, *GetHelloParams) (*GetHelloResult, error)
CreateForwarder(context.Context, *CreateForwarderParams) (*CreateForwarderResult, error)
ListForwarders(context.Context, *ListForwardersParams) (*ListForwardersResult, error)
DeleteForwarder(context.Context, *DeleteForwarderParams) (*DeleteForwarderResult, error)
mustEmbedUnimplementedControlServer() mustEmbedUnimplementedControlServer()
} }
@@ -62,6 +101,15 @@ type UnimplementedControlServer struct {
func (UnimplementedControlServer) GetHello(context.Context, *GetHelloParams) (*GetHelloResult, error) { func (UnimplementedControlServer) GetHello(context.Context, *GetHelloParams) (*GetHelloResult, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetHello not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetHello not implemented")
} }
func (UnimplementedControlServer) CreateForwarder(context.Context, *CreateForwarderParams) (*CreateForwarderResult, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateForwarder not implemented")
}
func (UnimplementedControlServer) ListForwarders(context.Context, *ListForwardersParams) (*ListForwardersResult, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListForwarders not implemented")
}
func (UnimplementedControlServer) DeleteForwarder(context.Context, *DeleteForwarderParams) (*DeleteForwarderResult, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteForwarder not implemented")
}
func (UnimplementedControlServer) mustEmbedUnimplementedControlServer() {} func (UnimplementedControlServer) mustEmbedUnimplementedControlServer() {}
// UnsafeControlServer may be embedded to opt out of forward compatibility for this service. // UnsafeControlServer may be embedded to opt out of forward compatibility for this service.
@@ -93,6 +141,60 @@ func _Control_GetHello_Handler(srv interface{}, ctx context.Context, dec func(in
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _Control_CreateForwarder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateForwarderParams)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ControlServer).CreateForwarder(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Control_CreateForwarder_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ControlServer).CreateForwarder(ctx, req.(*CreateForwarderParams))
}
return interceptor(ctx, in, info, handler)
}
func _Control_ListForwarders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListForwardersParams)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ControlServer).ListForwarders(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Control_ListForwarders_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ControlServer).ListForwarders(ctx, req.(*ListForwardersParams))
}
return interceptor(ctx, in, info, handler)
}
func _Control_DeleteForwarder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteForwarderParams)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ControlServer).DeleteForwarder(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Control_DeleteForwarder_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ControlServer).DeleteForwarder(ctx, req.(*DeleteForwarderParams))
}
return interceptor(ctx, in, info, handler)
}
// Control_ServiceDesc is the grpc.ServiceDesc for Control service. // Control_ServiceDesc is the grpc.ServiceDesc for Control service.
// It's only intended for direct use with grpc.RegisterService, // It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy) // and not to be introspected or modified (even as a copy)
@@ -104,6 +206,18 @@ var Control_ServiceDesc = grpc.ServiceDesc{
MethodName: "getHello", MethodName: "getHello",
Handler: _Control_GetHello_Handler, Handler: _Control_GetHello_Handler,
}, },
{
MethodName: "createForwarder",
Handler: _Control_CreateForwarder_Handler,
},
{
MethodName: "listForwarders",
Handler: _Control_ListForwarders_Handler,
},
{
MethodName: "deleteForwarder",
Handler: _Control_DeleteForwarder_Handler,
},
}, },
Streams: []grpc.StreamDesc{}, Streams: []grpc.StreamDesc{},
Metadata: "mlbctl.proto", Metadata: "mlbctl.proto",

37
pkg/network/listen.go Normal file
View File

@@ -0,0 +1,37 @@
package network
import (
"crypto/tls"
"net"
)
const protocol = "tcp"
func CreateTLSListener(addrinfo string, x509cert, x509key []byte) (net.Listener, error) {
var listen net.Listener
var err error
tlsCert, err := tls.X509KeyPair(x509cert, x509key)
if err != nil {
return listen, err
}
tlsConfig := tls.Config{
Certificates: []tls.Certificate{tlsCert},
ClientAuth: tls.NoClientCert,
InsecureSkipVerify: true,
}
listen, err = tls.Listen(protocol, addrinfo, &tlsConfig)
if err != nil {
return listen, err
}
return listen, err
}
func CreateListener(addrinfo string) (net.Listener, error) {
var listen net.Listener
var err error
listen, err = net.Listen(protocol, addrinfo)
if err != nil {
return listen, err
}
return listen, err
}

View File

@@ -11,7 +11,7 @@ import (
"time" "time"
) )
func CreateX509SelfSignedCert(subject string, hostnames ...string) ([]byte, []byte, error) { func CreateCertKey(subject string, hostnames ...string) ([]byte, []byte, error) {
var err error var err error
certPem := make([]byte, 0) certPem := make([]byte, 0)
@@ -72,7 +72,7 @@ func CreateX509SelfSignedCert(subject string, hostnames ...string) ([]byte, []by
return certPem, keyPem, err return certPem, keyPem, err
} }
func CreateX509CACert(commonName string) ([]byte, []byte, error) { func CreateCACert(commonName string) ([]byte, []byte, error) {
var err error var err error
certPem := make([]byte, 0) certPem := make([]byte, 0)
keyPem := make([]byte, 0) keyPem := make([]byte, 0)

View File

@@ -10,22 +10,16 @@ import (
) )
func TestCert(t *testing.T) { func TestCert(t *testing.T) {
{ {
//caCert, caKey, err := CreateX509SelfSignedCert("test1") caCert, caKey, err := CreateCertKey("test1")
//require.NoError(t, err) require.NoError(t, err)
//fmt.Println(string(caCert)) fmt.Println(string(caCert))
//fmt.Println(string(caKey)) fmt.Println(string(caKey))
} }
{ {
caCert, caKey, err := CreateX509CACert("test1") caCert, caKey, err := CreateCACert("test1")
require.NoError(t, err) require.NoError(t, err)
fmt.Println(string(caCert)) fmt.Println(string(caCert))
fmt.Println(string(caKey)) fmt.Println(string(caKey))
// caCert, caKey, err = CreateX509Cert("test1", caKey)
// require.NoError(t, err)
// fmt.Println(string(caCert))
// fmt.Println(string(caKey))
} }
} }

View File

@@ -6,10 +6,39 @@ package mlbctl;
service Control { service Control {
rpc getHello(getHelloParams) returns (getHelloResult) {}; rpc getHello(getHelloParams) returns (getHelloResult) {};
rpc createForwarder(createForwarderParams) returns (createForwarderResult) {};
rpc listForwarders(listForwardersParams) returns (listForwardersResult) {};
rpc deleteForwarder(deleteForwarderParams) returns (deleteForwarderResult) {};
} }
message getHelloParams {} message getHelloParams {}
message getHelloResult { message getHelloResult {
string message = 1; string message = 1;
} }
message forwarder {
uint32 lport = 1;
uint32 dport = 2;
repeated destination destinations = 3;
}
message destination {
string address = 1;
}
message listForwardersParams {}
message listForwardersResult {
repeated forwarder forwarders = 1;
}
message createForwarderParams {
uint32 lport = 1;
uint32 dport = 2;
repeated string destinations = 3;
}
message createForwarderResult {}
message deleteForwarderParams {
uint32 lport = 1;
}
message deleteForwarderResult {}