mirror of
https://github.com/fosrl/newt.git
synced 2026-03-05 18:26:42 +00:00
Update to use docker network checking against newt networking
This commit is contained in:
@@ -4,6 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -67,8 +69,44 @@ func CheckSocket(socketPath string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsWithinNewtNetwork checks if a provided target is within the newt network
|
||||||
|
func IsWithinNewtNetwork(socketPath string, containerNameAsHostname bool, targetAddress string, targetPort int) (bool, error) {
|
||||||
|
containers, err := ListContainers(socketPath, containerNameAsHostname)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("failed to list Docker containers: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we can find the passed hostname/ip in the networks or as the container name, it is valid and can add it
|
||||||
|
for _, c := range containers {
|
||||||
|
for _, network := range c.Networks {
|
||||||
|
//If the container name matches, check the ports being mapped too
|
||||||
|
if containerNameAsHostname {
|
||||||
|
if c.Name == targetAddress {
|
||||||
|
for _, port := range c.Ports {
|
||||||
|
if port.PublicPort == targetPort || port.PrivatePort == targetPort {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//If the ip address matches, check the ports being mapped too
|
||||||
|
if network.IPAddress == targetAddress {
|
||||||
|
for _, port := range c.Ports {
|
||||||
|
if port.PublicPort == targetPort || port.PrivatePort == targetPort {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
combinedTargetAddress := targetAddress + ":" + strconv.Itoa(targetPort)
|
||||||
|
return false, fmt.Errorf("target address not within newt network: %s", combinedTargetAddress)
|
||||||
|
}
|
||||||
|
|
||||||
// ListContainers lists all Docker containers with their network information
|
// ListContainers lists all Docker containers with their network information
|
||||||
func ListContainers(socketPath string) ([]Container, error) {
|
func ListContainers(socketPath string, containerNameAsHostname bool) ([]Container, error) {
|
||||||
// Use the provided socket path or default to standard location
|
// Use the provided socket path or default to standard location
|
||||||
if socketPath == "" {
|
if socketPath == "" {
|
||||||
socketPath = "/var/run/docker.sock"
|
socketPath = "/var/run/docker.sock"
|
||||||
@@ -88,6 +126,12 @@ func ListContainers(socketPath string) ([]Container, error) {
|
|||||||
}
|
}
|
||||||
defer cli.Close()
|
defer cli.Close()
|
||||||
|
|
||||||
|
// Get the newt container
|
||||||
|
newtContainer, err := getNewtContainer(ctx, cli)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to list containers: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// List containers
|
// List containers
|
||||||
containers, err := cli.ContainerList(ctx, container.ListOptions{All: true})
|
containers, err := cli.ContainerList(ctx, container.ListOptions{All: true})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -96,6 +140,12 @@ func ListContainers(socketPath string) ([]Container, error) {
|
|||||||
|
|
||||||
var dockerContainers []Container
|
var dockerContainers []Container
|
||||||
for _, c := range containers {
|
for _, c := range containers {
|
||||||
|
// Get container name (remove leading slash)
|
||||||
|
name := ""
|
||||||
|
if len(c.Names) > 0 {
|
||||||
|
name = strings.TrimPrefix(c.Names[0], "/")
|
||||||
|
}
|
||||||
|
|
||||||
// Convert ports
|
// Convert ports
|
||||||
var ports []Port
|
var ports []Port
|
||||||
for _, port := range c.Ports {
|
for _, port := range c.Ports {
|
||||||
@@ -112,29 +162,32 @@ func ListContainers(socketPath string) ([]Container, error) {
|
|||||||
ports = append(ports, dockerPort)
|
ports = append(ports, dockerPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get container name (remove leading slash)
|
|
||||||
name := ""
|
|
||||||
if len(c.Names) > 0 {
|
|
||||||
name = strings.TrimPrefix(c.Names[0], "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get network information by inspecting the container
|
// Get network information by inspecting the container
|
||||||
networks := make(map[string]Network)
|
networks := make(map[string]Network)
|
||||||
|
|
||||||
// Inspect container to get detailed network information
|
// Inspect the container to get detailed network information
|
||||||
containerInfo, err := cli.ContainerInspect(ctx, c.ID)
|
containerInfo, err := cli.ContainerInspect(ctx, c.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Debug("Failed to inspect container %s for network info: %v", c.ID[:12], err)
|
logger.Debug("Failed to inspect container %s for network info: %v", c.ID[:12], err)
|
||||||
// Continue without network info if inspection fails
|
// Continue without network info if inspection fails
|
||||||
} else {
|
} else {
|
||||||
|
// Only containers within the newt network will be returned
|
||||||
|
isInNewtNetwork := false
|
||||||
|
|
||||||
// Extract network information from inspection
|
// Extract network information from inspection
|
||||||
if containerInfo.NetworkSettings != nil && containerInfo.NetworkSettings.Networks != nil {
|
if containerInfo.NetworkSettings != nil && containerInfo.NetworkSettings.Networks != nil {
|
||||||
for networkName, endpoint := range containerInfo.NetworkSettings.Networks {
|
for networkName, endpoint := range containerInfo.NetworkSettings.Networks {
|
||||||
|
// Determine if the current container is in the newt network
|
||||||
|
for _, newtNetwork := range newtContainer.NetworkSettings.Networks {
|
||||||
|
if !isInNewtNetwork {
|
||||||
|
isInNewtNetwork = endpoint.NetworkID == newtNetwork.NetworkID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dockerNetwork := Network{
|
dockerNetwork := Network{
|
||||||
NetworkID: endpoint.NetworkID,
|
NetworkID: endpoint.NetworkID,
|
||||||
EndpointID: endpoint.EndpointID,
|
EndpointID: endpoint.EndpointID,
|
||||||
Gateway: endpoint.Gateway,
|
Gateway: endpoint.Gateway,
|
||||||
IPAddress: endpoint.IPAddress,
|
|
||||||
IPPrefixLen: endpoint.IPPrefixLen,
|
IPPrefixLen: endpoint.IPPrefixLen,
|
||||||
IPv6Gateway: endpoint.IPv6Gateway,
|
IPv6Gateway: endpoint.IPv6Gateway,
|
||||||
GlobalIPv6Address: endpoint.GlobalIPv6Address,
|
GlobalIPv6Address: endpoint.GlobalIPv6Address,
|
||||||
@@ -143,9 +196,21 @@ func ListContainers(socketPath string) ([]Container, error) {
|
|||||||
Aliases: endpoint.Aliases,
|
Aliases: endpoint.Aliases,
|
||||||
DNSNames: endpoint.DNSNames,
|
DNSNames: endpoint.DNSNames,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't set the IP address if container name is used as hostname
|
||||||
|
if !containerNameAsHostname {
|
||||||
|
dockerNetwork.IPAddress = endpoint.IPAddress
|
||||||
|
}
|
||||||
|
|
||||||
networks[networkName] = dockerNetwork
|
networks[networkName] = dockerNetwork
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't continue returning this container if not in the newt network(s)
|
||||||
|
if !isInNewtNetwork {
|
||||||
|
logger.Debug("container not found within the newt network, skipping: %s", name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dockerContainer := Container{
|
dockerContainer := Container{
|
||||||
@@ -164,3 +229,19 @@ func ListContainers(socketPath string) ([]Container, error) {
|
|||||||
|
|
||||||
return dockerContainers, nil
|
return dockerContainers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getNewtContainer(dockerContext context.Context, dockerClient *client.Client) (*container.InspectResponse, error) {
|
||||||
|
// Get newt hostname from the os
|
||||||
|
newtContainerName, err := os.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to find newt hostname: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get newt container from the docker socket
|
||||||
|
newtContainer, err := dockerClient.ContainerInspect(dockerContext, newtContainerName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to find newt container: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &newtContainer, nil
|
||||||
|
}
|
||||||
55
main.go
55
main.go
@@ -341,18 +341,20 @@ func resolveDomain(domain string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
endpoint string
|
endpoint string
|
||||||
id string
|
id string
|
||||||
secret string
|
secret string
|
||||||
mtu string
|
mtu string
|
||||||
mtuInt int
|
mtuInt int
|
||||||
dns string
|
dns string
|
||||||
privateKey wgtypes.Key
|
privateKey wgtypes.Key
|
||||||
err error
|
err error
|
||||||
logLevel string
|
logLevel string
|
||||||
updownScript string
|
updownScript string
|
||||||
tlsPrivateKey string
|
tlsPrivateKey string
|
||||||
dockerSocket string
|
dockerSocket string
|
||||||
|
dockerContainerAsHostname string
|
||||||
|
dockerContainerAsHostnameBool bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -366,6 +368,7 @@ func main() {
|
|||||||
updownScript = os.Getenv("UPDOWN_SCRIPT")
|
updownScript = os.Getenv("UPDOWN_SCRIPT")
|
||||||
tlsPrivateKey = os.Getenv("TLS_CLIENT_CERT")
|
tlsPrivateKey = os.Getenv("TLS_CLIENT_CERT")
|
||||||
dockerSocket = os.Getenv("DOCKER_SOCKET")
|
dockerSocket = os.Getenv("DOCKER_SOCKET")
|
||||||
|
dockerContainerAsHostname = os.Getenv("DOCKER_CONTAINER_NAME_AS_HOSTNAME")
|
||||||
|
|
||||||
if endpoint == "" {
|
if endpoint == "" {
|
||||||
flag.StringVar(&endpoint, "endpoint", "", "Endpoint of your pangolin server")
|
flag.StringVar(&endpoint, "endpoint", "", "Endpoint of your pangolin server")
|
||||||
@@ -394,6 +397,9 @@ func main() {
|
|||||||
if dockerSocket == "" {
|
if dockerSocket == "" {
|
||||||
flag.StringVar(&dockerSocket, "docker-socket", "", "Path to Docker socket (typically /var/run/docker.sock)")
|
flag.StringVar(&dockerSocket, "docker-socket", "", "Path to Docker socket (typically /var/run/docker.sock)")
|
||||||
}
|
}
|
||||||
|
if dockerContainerAsHostname == "" {
|
||||||
|
flag.StringVar(&dockerContainerAsHostname, "docker-container-name-as-hostname", "false", "Use container name when hostname for networking (true or false)")
|
||||||
|
}
|
||||||
|
|
||||||
// do a --version check
|
// do a --version check
|
||||||
version := flag.Bool("version", false, "Print the version")
|
version := flag.Bool("version", false, "Print the version")
|
||||||
@@ -418,6 +424,13 @@ func main() {
|
|||||||
logger.Fatal("Failed to parse MTU: %v", err)
|
logger.Fatal("Failed to parse MTU: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pase if to use hostname over ip address for network sent to pangolin
|
||||||
|
dockerContainerAsHostnameBool, err = strconv.ParseBool(dockerContainerAsHostname)
|
||||||
|
if err != nil {
|
||||||
|
logger.Info("Docker use container name cannot be parsed. Defaulting to 'false'")
|
||||||
|
dockerContainerAsHostnameBool = false
|
||||||
|
}
|
||||||
|
|
||||||
privateKey, err = wgtypes.GeneratePrivateKey()
|
privateKey, err = wgtypes.GeneratePrivateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal("Failed to generate private key: %v", err)
|
logger.Fatal("Failed to generate private key: %v", err)
|
||||||
@@ -676,7 +689,7 @@ persistent_keepalive_interval=5`, fixKey(privateKey.String()), fixKey(wgData.Pub
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List Docker containers
|
// List Docker containers
|
||||||
containers, err := docker.ListContainers(dockerSocket)
|
containers, err := docker.ListContainers(dockerSocket, dockerContainerAsHostnameBool)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to list Docker containers: %v", err)
|
logger.Error("Failed to list Docker containers: %v", err)
|
||||||
return
|
return
|
||||||
@@ -760,12 +773,14 @@ func updateTargets(pm *proxy.ProxyManager, action string, tunnelIP string, proto
|
|||||||
}
|
}
|
||||||
|
|
||||||
if action == "add" {
|
if action == "add" {
|
||||||
target := parts[1] + ":" + parts[2]
|
targetAddress := parts[1]
|
||||||
|
targetPort, _ := strconv.Atoi(parts[2])
|
||||||
|
combinedAddress := targetAddress + ":" + parts[2]
|
||||||
|
|
||||||
// Call updown script if provided
|
// Call updown script if provided
|
||||||
processedTarget := target
|
processedTarget := combinedAddress
|
||||||
if updownScript != "" {
|
if updownScript != "" {
|
||||||
newTarget, err := executeUpdownScript(action, proto, target)
|
newTarget, err := executeUpdownScript(action, proto, combinedAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warn("Updown script error: %v", err)
|
logger.Warn("Updown script error: %v", err)
|
||||||
} else if newTarget != "" {
|
} else if newTarget != "" {
|
||||||
@@ -783,8 +798,12 @@ func updateTargets(pm *proxy.ProxyManager, action string, tunnelIP string, proto
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add the new target
|
// Add the new target
|
||||||
pm.AddTarget(proto, tunnelIP, port, processedTarget)
|
isWithinNewtNetwork, err := docker.IsWithinNewtNetwork(dockerSocket, dockerContainerAsHostnameBool, targetAddress, targetPort)
|
||||||
|
if !isWithinNewtNetwork {
|
||||||
|
logger.Error("Not adding target: %v", err)
|
||||||
|
} else {
|
||||||
|
pm.AddTarget(proto, tunnelIP, port, processedTarget)
|
||||||
|
}
|
||||||
} else if action == "remove" {
|
} else if action == "remove" {
|
||||||
logger.Info("Removing target with port %d", port)
|
logger.Info("Removing target with port %d", port)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user