2020-08-11 04:38:42 +00:00
|
|
|
package environment
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"github.com/docker/go-connections/nat"
|
2020-09-07 22:33:47 +00:00
|
|
|
"github.com/pterodactyl/wings/config"
|
2020-08-11 04:38:42 +00:00
|
|
|
"strconv"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Defines the allocations available for a given server. When using the Docker environment
|
|
|
|
// driver these correspond to mappings for the container that allow external connections.
|
|
|
|
type Allocations struct {
|
|
|
|
// Defines the default allocation that should be used for this server. This is
|
|
|
|
// what will be used for {SERVER_IP} and {SERVER_PORT} when modifying configuration
|
|
|
|
// files or the startup arguments for a server.
|
|
|
|
DefaultMapping struct {
|
|
|
|
Ip string `json:"ip"`
|
|
|
|
Port int `json:"port"`
|
|
|
|
} `json:"default"`
|
|
|
|
|
|
|
|
// Mappings contains all of the ports that should be assigned to a given server
|
|
|
|
// attached to the IP they correspond to.
|
|
|
|
Mappings map[string][]int `json:"mappings"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// Converts the server allocation mappings into a format that can be understood by Docker. While
|
|
|
|
// we do strive to support multiple environments, using Docker's standardized format for the
|
|
|
|
// bindings certainly makes life a little easier for managing things.
|
2020-09-07 22:33:47 +00:00
|
|
|
//
|
|
|
|
// You'll want to use DockerBindings() if you need to re-map 127.0.0.1 to the Docker interface.
|
2020-08-11 04:38:42 +00:00
|
|
|
func (a *Allocations) Bindings() nat.PortMap {
|
|
|
|
var out = nat.PortMap{}
|
|
|
|
|
|
|
|
for ip, ports := range a.Mappings {
|
|
|
|
for _, port := range ports {
|
|
|
|
// Skip over invalid ports.
|
|
|
|
if port < 1 || port > 65535 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-12-01 19:43:40 +00:00
|
|
|
binding := nat.PortBinding{
|
|
|
|
HostIP: ip,
|
|
|
|
HostPort: strconv.Itoa(port),
|
2020-08-11 04:38:42 +00:00
|
|
|
}
|
|
|
|
|
2020-12-01 19:43:40 +00:00
|
|
|
tcpPort, ok := out[nat.Port(fmt.Sprintf("%d/tcp", port))]
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
out[nat.Port(fmt.Sprintf("%d/tcp", port))] = []nat.PortBinding{binding}
|
|
|
|
} else {
|
|
|
|
out[nat.Port(fmt.Sprintf("%d/tcp", port))] = append(tcpPort, binding)
|
|
|
|
}
|
|
|
|
|
|
|
|
udpPort, ok := out[nat.Port(fmt.Sprintf("%d/udp", port))]
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
out[nat.Port(fmt.Sprintf("%d/udp", port))] = []nat.PortBinding{binding}
|
|
|
|
} else {
|
|
|
|
out[nat.Port(fmt.Sprintf("%d/udp", port))] = append(udpPort, binding)
|
|
|
|
}
|
2020-08-11 04:38:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2020-09-07 22:33:47 +00:00
|
|
|
// Returns the bindings for the server in a way that is supported correctly by Docker. This replaces
|
|
|
|
// any reference to 127.0.0.1 with the IP of the pterodactyl0 network interface which will allow the
|
|
|
|
// server to operate on a local address while still being accessible by other containers.
|
|
|
|
func (a *Allocations) DockerBindings() nat.PortMap {
|
|
|
|
iface := config.Get().Docker.Network.Interface
|
|
|
|
|
|
|
|
out := a.Bindings()
|
|
|
|
// Loop over all of the bindings for this container, and convert any that reference 127.0.0.1
|
|
|
|
// to use the pterodactyl0 network interface IP, as that is the true local for what people are
|
|
|
|
// trying to do when creating servers.
|
|
|
|
for p, binds := range out {
|
|
|
|
for i, alloc := range binds {
|
|
|
|
if alloc.HostIP != "127.0.0.1" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// If using ISPN just delete the local allocation from the server.
|
|
|
|
if config.Get().Docker.Network.ISPN {
|
|
|
|
out[p] = append(out[p][:i], out[p][i+1:]...)
|
|
|
|
} else {
|
|
|
|
out[p][i] = nat.PortBinding{
|
|
|
|
HostIP: iface,
|
|
|
|
HostPort: alloc.HostPort,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2020-08-11 04:38:42 +00:00
|
|
|
// Converts the server allocation mappings into a PortSet that can be understood
|
|
|
|
// by Docker. This formatting is slightly different than "Bindings" as it should
|
|
|
|
// return an empty struct rather than a binding.
|
|
|
|
//
|
2020-09-07 22:33:47 +00:00
|
|
|
// To accomplish this, we'll just get the values from "DockerBindings" and then set them
|
2020-08-11 04:38:42 +00:00
|
|
|
// to empty structs. Because why not.
|
|
|
|
func (a *Allocations) Exposed() nat.PortSet {
|
|
|
|
var out = nat.PortSet{}
|
|
|
|
|
2020-09-07 22:33:47 +00:00
|
|
|
for port := range a.DockerBindings() {
|
2020-08-11 04:38:42 +00:00
|
|
|
out[port] = struct{}{}
|
|
|
|
}
|
|
|
|
|
|
|
|
return out
|
2020-09-05 19:08:40 +00:00
|
|
|
}
|