mirror of https://github.com/xSmurf/oz.git
parent
0f682806ab
commit
e4da051f83
@ -0,0 +1,202 @@
|
||||
package network
|
||||
|
||||
import(
|
||||
//Builtin
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/subgraph/oz/ns"
|
||||
|
||||
"github.com/op/go-logging"
|
||||
)
|
||||
|
||||
// Socket list, used to hold ports that should be forwarded
|
||||
type ProxyConfig struct {
|
||||
// One of client, server
|
||||
Nettype string `json:"type"`
|
||||
|
||||
// One of tcp, udp, socket
|
||||
Proto string
|
||||
|
||||
// TCP or UDP port number
|
||||
Port int
|
||||
|
||||
// Unix socket to attach to
|
||||
// applies to proto: socket only
|
||||
Socket string
|
||||
|
||||
// Optional: Destination address
|
||||
// In client mode: the host side address to connect to
|
||||
// In server mode: the container side address to bind to
|
||||
// If left empty, localhost is used
|
||||
Destination string
|
||||
}
|
||||
|
||||
var wgProxy sync.WaitGroup
|
||||
|
||||
func ProxySetup(childPid int, ozSockets []ProxyConfig, log *logging.Logger, ready sync.WaitGroup) error {
|
||||
for _, socket := range ozSockets {
|
||||
if socket.Nettype == "" || socket.Nettype == "client" {
|
||||
err := newProxyClient(childPid, socket.Proto, socket.Destination, socket.Port, log, ready)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to setup client socket forwarding %+v, %s", socket, err)
|
||||
}
|
||||
} else if socket.Nettype == "server" {
|
||||
err := newProxyServer(childPid, socket.Proto, socket.Destination, socket.Port, log, ready)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to setup server socket forwarding %+s, %s", socket, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener/Client
|
||||
**/
|
||||
func proxyClientConn(conn *net.Conn, proto, rAddr string, ready sync.WaitGroup) error {
|
||||
rConn, err := net.Dial(proto, rAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Socket: %+v.\n", err)
|
||||
}
|
||||
|
||||
go io.Copy(rConn, *conn)
|
||||
go io.Copy(*conn, rConn)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newProxyClient(pid int, proto, dest string, port int, log *logging.Logger, ready sync.WaitGroup) error {
|
||||
if dest == "" {
|
||||
dest = "127.0.0.1"
|
||||
}
|
||||
|
||||
lAddr := net.JoinHostPort("127.0.0.1", strconv.Itoa(port))
|
||||
rAddr := net.JoinHostPort(dest, strconv.Itoa(port))
|
||||
|
||||
log.Info("Starting socket client forwarding: %s://%s.", proto, rAddr)
|
||||
|
||||
listen, err := proxySocketListener(pid, proto, lAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wgProxy.Add(1)
|
||||
go func() {
|
||||
defer wgProxy.Done()
|
||||
for {
|
||||
conn, err := listen.Accept()
|
||||
if err != nil {
|
||||
log.Error("Socket: %+v.", err)
|
||||
//panic(err)
|
||||
continue
|
||||
}
|
||||
|
||||
go proxyClientConn(&conn, proto, rAddr, ready)
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func proxySocketListener(pid int, proto, lAddr string) (net.Listener, error) {
|
||||
fd, err := ns.OpenProcess(pid, ns.CLONE_NEWNET)
|
||||
defer ns.Close(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nsSocketListener(fd, proto, lAddr)
|
||||
}
|
||||
|
||||
func nsSocketListener(fd uintptr, proto, lAddr string) (net.Listener, error) {
|
||||
origNs, _ := ns.OpenProcess(os.Getpid(), ns.CLONE_NEWNET)
|
||||
defer ns.Close(origNs)
|
||||
defer ns.Set(origNs, ns.CLONE_NEWNET)
|
||||
|
||||
err := ns.Set(uintptr(fd), ns.CLONE_NEWNET)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return net.Listen(proto, lAddr)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect/Server
|
||||
**/
|
||||
func proxyServerConn(pid int, conn *net.Conn, proto, rAddr string, log *logging.Logger, ready sync.WaitGroup) (error) {
|
||||
rConn, err := socketConnect(pid, proto, rAddr)
|
||||
if err != nil {
|
||||
log.Error("Socket: %+v.", err)
|
||||
return err
|
||||
}
|
||||
|
||||
go io.Copy(*conn, rConn)
|
||||
go io.Copy(rConn, *conn)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newProxyServer(pid int, proto, dest string, port int, log *logging.Logger, ready sync.WaitGroup) (error) {
|
||||
if dest == "" {
|
||||
dest = "127.0.0.1"
|
||||
}
|
||||
|
||||
lAddr := net.JoinHostPort(dest, strconv.Itoa(port))
|
||||
rAddr := net.JoinHostPort("127.0.0.1", strconv.Itoa(port))
|
||||
|
||||
log.Info("Starting socket server forwarding: %s://%s.", proto, lAddr)
|
||||
|
||||
listen, err := net.Listen(proto, lAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wgProxy.Add(1)
|
||||
go func() {
|
||||
defer wgProxy.Done()
|
||||
for {
|
||||
conn, err := listen.Accept()
|
||||
if err != nil {
|
||||
log.Error("Socket: %+v.", err)
|
||||
//panic(err)
|
||||
continue
|
||||
}
|
||||
|
||||
go proxyServerConn(pid, &conn, proto, rAddr, log, ready)
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func socketConnect(pid int, proto, rAddr string) (net.Conn, error) {
|
||||
fd, err := ns.OpenProcess(pid, ns.CLONE_NEWNET)
|
||||
defer ns.Close(fd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nsProxySocketConnect(fd, proto, rAddr)
|
||||
}
|
||||
|
||||
func nsProxySocketConnect(fd uintptr, proto, rAddr string) (net.Conn, error) {
|
||||
origNs, _ := ns.OpenProcess(os.Getpid(), ns.CLONE_NEWNET)
|
||||
defer ns.Close(origNs)
|
||||
defer ns.Set(origNs, ns.CLONE_NEWNET)
|
||||
|
||||
err := ns.Set(uintptr(fd), ns.CLONE_NEWNET)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return net.Dial(proto, rAddr)
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package ns
|
||||
|
||||
import (
|
||||
|
||||
)
|
||||
|
||||
const (
|
||||
SYS_SETNS = 308
|
||||
)
|
@ -0,0 +1,86 @@
|
||||
package ns
|
||||
|
||||
import(
|
||||
"syscall"
|
||||
"errors"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Namespace struct {
|
||||
Path string
|
||||
Type uintptr
|
||||
}
|
||||
|
||||
const (
|
||||
CLONE_NEWNS = syscall.CLONE_NEWNS
|
||||
CLONE_NEWUTS = syscall.CLONE_NEWUTS
|
||||
CLONE_NEWIPC = syscall.CLONE_NEWIPC
|
||||
CLONE_NEWNET = syscall.CLONE_NEWNET
|
||||
CLONE_NEWUSER = syscall.CLONE_NEWUSER
|
||||
CLONE_NEWPID = syscall.CLONE_NEWPID
|
||||
)
|
||||
|
||||
var (
|
||||
Types []Namespace
|
||||
)
|
||||
|
||||
func init() {
|
||||
Types = []Namespace{
|
||||
Namespace{Path: "ns/user", Type: syscall.CLONE_NEWUSER},
|
||||
Namespace{Path: "ns/ipc", Type: syscall.CLONE_NEWIPC},
|
||||
Namespace{Path: "ns/uts", Type: syscall.CLONE_NEWUTS},
|
||||
Namespace{Path: "ns/net", Type: syscall.CLONE_NEWNET},
|
||||
Namespace{Path: "ns/pid", Type: syscall.CLONE_NEWPID},
|
||||
Namespace{Path: "ns/mnt", Type: syscall.CLONE_NEWNS},
|
||||
}
|
||||
}
|
||||
|
||||
func Set(fd, nsType uintptr) (error) {
|
||||
_, _, err := syscall.Syscall(SYS_SETNS, uintptr(fd), uintptr(nsType), 0)
|
||||
if err != 0 {
|
||||
return errors.New("Unable to set namespace")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetPath(pid int, nsType uintptr) (string, error) {
|
||||
var nsPath string
|
||||
|
||||
for _, n := range Types {
|
||||
if n.Type == nsType {
|
||||
nsPath = path.Join("/", "proc", strconv.Itoa(pid), n.Path)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if nsPath == "" {
|
||||
return "", errors.New("Unable to find namespace type")
|
||||
}
|
||||
|
||||
return nsPath, nil
|
||||
}
|
||||
|
||||
func OpenProcess(pid int, nsType uintptr) (uintptr, error) {
|
||||
nsPath, err := GetPath(pid, nsType)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return Open(nsPath)
|
||||
}
|
||||
|
||||
func Open(nsPath string) (uintptr, error) {
|
||||
fd, err := os.Open(nsPath)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return fd.Fd(), nil
|
||||
}
|
||||
|
||||
func Close(fd uintptr) (error) {
|
||||
return syscall.Close(int(fd))
|
||||
}
|
Loading…
Reference in new issue