2023-11-16 22:50:21 +03:00
|
|
|
package docker
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net"
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/Neur0toxine/sshpoke/internal/logger"
|
2023-11-18 12:36:17 +03:00
|
|
|
"github.com/Neur0toxine/sshpoke/pkg/dto"
|
2023-11-16 22:50:21 +03:00
|
|
|
"github.com/docker/docker/api/types"
|
|
|
|
"github.com/docker/docker/api/types/events"
|
|
|
|
"github.com/docker/docker/api/types/network"
|
|
|
|
"github.com/mitchellh/mapstructure"
|
|
|
|
)
|
|
|
|
|
|
|
|
type labelsConfig struct {
|
|
|
|
Enable boolStr `mapstructure:"sshpoke.enable"`
|
|
|
|
Network string `mapstructure:"sshpoke.network"`
|
|
|
|
Server string `mapstructure:"sshpoke.server"`
|
|
|
|
Port string `mapstructure:"sshpoke.port"`
|
2023-11-17 20:39:00 +03:00
|
|
|
Prefix string `mapstructure:"sshpoke.prefix"`
|
2023-11-16 22:50:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type boolStr string
|
|
|
|
|
|
|
|
func (b boolStr) Bool() bool {
|
|
|
|
return string(b) == "true"
|
|
|
|
}
|
|
|
|
|
|
|
|
func actorEnabled(actor events.Actor) bool {
|
|
|
|
label, ok := actor.Attributes["sshpoke.enable"]
|
|
|
|
if !ok {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return boolStr(label).Bool()
|
|
|
|
}
|
|
|
|
|
2023-11-18 12:36:17 +03:00
|
|
|
func dockerContainerToInternal(container types.Container) (result dto.Container, ok bool) {
|
2023-11-16 22:50:21 +03:00
|
|
|
var labels labelsConfig
|
|
|
|
if err := mapstructure.Decode(container.Labels, &labels); err != nil {
|
|
|
|
logger.Sugar.Debugf("skipping container %s because configuration is invalid: %s", container.ID, err)
|
|
|
|
return result, false
|
|
|
|
}
|
|
|
|
if !labels.Enable.Bool() {
|
|
|
|
logger.Sugar.Debugf("skipping container %s because sshpoke is not enabled for it", container.ID)
|
|
|
|
return result, false
|
|
|
|
}
|
|
|
|
if labels.Server == "" {
|
|
|
|
logger.Sugar.Debugf("skipping container %s because 'sshpoke.server' is not defined", container.ID)
|
|
|
|
return result, false
|
|
|
|
}
|
|
|
|
if container.NetworkSettings == nil ||
|
|
|
|
container.NetworkSettings.Networks == nil ||
|
|
|
|
len(container.NetworkSettings.Networks) == 0 {
|
|
|
|
logger.Sugar.Debugf("skipping container %s because network settings are empty", container.ID)
|
|
|
|
return result, false
|
|
|
|
}
|
|
|
|
var ip net.IP
|
|
|
|
if len(container.NetworkSettings.Networks) == 1 {
|
|
|
|
ip = net.ParseIP(getKeyVal(container.NetworkSettings.Networks).IPAddress)
|
|
|
|
} else {
|
|
|
|
if labels.Network == "" {
|
|
|
|
logger.Sugar.Debugf("container %s has %d networks and 'sshpoke.network' label is not specified",
|
|
|
|
container.ID, len(container.NetworkSettings.Networks))
|
|
|
|
return result, false
|
|
|
|
}
|
|
|
|
ntwrk, exists := container.NetworkSettings.Networks[labels.Network]
|
|
|
|
if !exists {
|
|
|
|
logger.Sugar.Debugf("container %s does not have network %s", container.ID, labels.Network)
|
|
|
|
return result, false
|
|
|
|
}
|
|
|
|
ip = net.ParseIP(ntwrk.IPAddress)
|
|
|
|
}
|
|
|
|
port, err := strconv.Atoi(labels.Port)
|
|
|
|
if err != nil {
|
|
|
|
logger.Sugar.Debugf("skipping container %s because 'sshpoke.port' is not numeric", container.ID)
|
|
|
|
return result, false
|
|
|
|
}
|
|
|
|
|
2023-11-18 12:36:17 +03:00
|
|
|
return dto.Container{
|
2023-11-16 22:50:21 +03:00
|
|
|
IP: ip,
|
|
|
|
Port: uint16(port),
|
|
|
|
Server: labels.Server,
|
2023-11-17 20:39:00 +03:00
|
|
|
Prefix: labels.Prefix,
|
2023-11-16 22:50:21 +03:00
|
|
|
}, true
|
|
|
|
}
|
|
|
|
|
|
|
|
func getKeyVal(m map[string]*network.EndpointSettings) *network.EndpointSettings {
|
|
|
|
for _, v := range m {
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|