Docker-DCO-1.1-Signed-off-by: Ian Bishop <ianbishop@pace7.com> (github: porjo)
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"net" |
| 7 | 7 |
"os" |
| 8 | 8 |
"strconv" |
| 9 |
+ "strings" |
|
| 9 | 10 |
"sync" |
| 10 | 11 |
|
| 11 | 12 |
log "github.com/Sirupsen/logrus" |
| ... | ... |
@@ -501,35 +502,48 @@ func AllocatePort(job *engine.Job) engine.Status {
|
| 501 | 501 |
func LinkContainers(job *engine.Job) engine.Status {
|
| 502 | 502 |
var ( |
| 503 | 503 |
action = job.Args[0] |
| 504 |
+ nfAction iptables.Action |
|
| 504 | 505 |
childIP = job.Getenv("ChildIP")
|
| 505 | 506 |
parentIP = job.Getenv("ParentIP")
|
| 506 | 507 |
ignoreErrors = job.GetenvBool("IgnoreErrors")
|
| 507 | 508 |
ports = job.GetenvList("Ports")
|
| 509 |
+ chain = iptables.Chain{}
|
|
| 508 | 510 |
) |
| 509 |
- for _, value := range ports {
|
|
| 510 |
- port := nat.Port(value) |
|
| 511 |
- if output, err := iptables.Raw(action, "FORWARD", |
|
| 512 |
- "-i", bridgeIface, "-o", bridgeIface, |
|
| 513 |
- "-p", port.Proto(), |
|
| 514 |
- "-s", parentIP, |
|
| 515 |
- "--dport", strconv.Itoa(port.Int()), |
|
| 516 |
- "-d", childIP, |
|
| 517 |
- "-j", "ACCEPT"); !ignoreErrors && err != nil {
|
|
| 518 |
- return job.Error(err) |
|
| 519 |
- } else if len(output) != 0 {
|
|
| 520 |
- return job.Errorf("Error toggle iptables forward: %s", output)
|
|
| 521 |
- } |
|
| 511 |
+ split := func(p string) (string, string) {
|
|
| 512 |
+ parts := strings.Split(p, "/") |
|
| 513 |
+ return parts[0], parts[1] |
|
| 514 |
+ } |
|
| 515 |
+ |
|
| 516 |
+ switch action {
|
|
| 517 |
+ case "-A": |
|
| 518 |
+ nfAction = iptables.Append |
|
| 519 |
+ case "-I": |
|
| 520 |
+ nfAction = iptables.Insert |
|
| 521 |
+ case "-D": |
|
| 522 |
+ nfAction = iptables.Delete |
|
| 523 |
+ default: |
|
| 524 |
+ return job.Errorf("Invalid action '%s' specified", action)
|
|
| 525 |
+ } |
|
| 522 | 526 |
|
| 523 |
- if output, err := iptables.Raw(action, "FORWARD", |
|
| 524 |
- "-i", bridgeIface, "-o", bridgeIface, |
|
| 525 |
- "-p", port.Proto(), |
|
| 526 |
- "-s", childIP, |
|
| 527 |
- "--sport", strconv.Itoa(port.Int()), |
|
| 528 |
- "-d", parentIP, |
|
| 529 |
- "-j", "ACCEPT"); !ignoreErrors && err != nil {
|
|
| 527 |
+ ip1 := net.ParseIP(parentIP) |
|
| 528 |
+ if ip1 == nil {
|
|
| 529 |
+ return job.Errorf("parent IP '%s' is invalid", parentIP)
|
|
| 530 |
+ } |
|
| 531 |
+ ip2 := net.ParseIP(childIP) |
|
| 532 |
+ if ip2 == nil {
|
|
| 533 |
+ return job.Errorf("child IP '%s' is invalid", childIP)
|
|
| 534 |
+ } |
|
| 535 |
+ |
|
| 536 |
+ chain.Name = "DOCKER" |
|
| 537 |
+ chain.Bridge = bridgeIface |
|
| 538 |
+ for _, p := range ports {
|
|
| 539 |
+ portStr, proto := split(p) |
|
| 540 |
+ port, err := strconv.Atoi(portStr) |
|
| 541 |
+ if !ignoreErrors && err != nil {
|
|
| 542 |
+ return job.Errorf("port '%s' is invalid", portStr)
|
|
| 543 |
+ } |
|
| 544 |
+ if err := chain.Link(nfAction, ip1, ip2, port, proto); !ignoreErrors && err != nil {
|
|
| 530 | 545 |
return job.Error(err) |
| 531 |
- } else if len(output) != 0 {
|
|
| 532 |
- return job.Errorf("Error toggle iptables forward: %s", output)
|
|
| 533 | 546 |
} |
| 534 | 547 |
} |
| 535 | 548 |
return engine.StatusOK |
| ... | ... |
@@ -93,7 +93,7 @@ func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err er |
| 93 | 93 |
} |
| 94 | 94 |
|
| 95 | 95 |
containerIP, containerPort := getIPAndPort(m.container) |
| 96 |
- if err := forward(iptables.Add, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
|
|
| 96 |
+ if err := forward(iptables.Append, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
|
|
| 97 | 97 |
return nil, err |
| 98 | 98 |
} |
| 99 | 99 |
|
| ... | ... |
@@ -138,7 +138,8 @@ func (l *Link) getDefaultPort() *nat.Port {
|
| 138 | 138 |
} |
| 139 | 139 |
|
| 140 | 140 |
func (l *Link) Enable() error {
|
| 141 |
- if err := l.toggle("-I", false); err != nil {
|
|
| 141 |
+ // -A == iptables append flag |
|
| 142 |
+ if err := l.toggle("-A", false); err != nil {
|
|
| 142 | 143 |
return err |
| 143 | 144 |
} |
| 144 | 145 |
l.IsEnabled = true |
| ... | ... |
@@ -148,6 +149,7 @@ func (l *Link) Enable() error {
|
| 148 | 148 |
func (l *Link) Disable() {
|
| 149 | 149 |
// We do not care about errors here because the link may not |
| 150 | 150 |
// exist in iptables |
| 151 |
+ // -D == iptables delete flag |
|
| 151 | 152 |
l.toggle("-D", true)
|
| 152 | 153 |
|
| 153 | 154 |
l.IsEnabled = false |
| ... | ... |
@@ -15,8 +15,9 @@ import ( |
| 15 | 15 |
type Action string |
| 16 | 16 |
|
| 17 | 17 |
const ( |
| 18 |
- Add Action = "-A" |
|
| 18 |
+ Append Action = "-A" |
|
| 19 | 19 |
Delete Action = "-D" |
| 20 |
+ Insert Action = "-I" |
|
| 20 | 21 |
) |
| 21 | 22 |
|
| 22 | 23 |
var ( |
| ... | ... |
@@ -54,10 +55,10 @@ func NewChain(name, bridge string) (*Chain, error) {
|
| 54 | 54 |
Bridge: bridge, |
| 55 | 55 |
} |
| 56 | 56 |
|
| 57 |
- if err := chain.Prerouting(Add, "-m", "addrtype", "--dst-type", "LOCAL"); err != nil {
|
|
| 57 |
+ if err := chain.Prerouting(Append, "-m", "addrtype", "--dst-type", "LOCAL"); err != nil {
|
|
| 58 | 58 |
return nil, fmt.Errorf("Failed to inject docker in PREROUTING chain: %s", err)
|
| 59 | 59 |
} |
| 60 |
- if err := chain.Output(Add, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", "127.0.0.0/8"); err != nil {
|
|
| 60 |
+ if err := chain.Output(Append, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", "127.0.0.0/8"); err != nil {
|
|
| 61 | 61 |
return nil, fmt.Errorf("Failed to inject docker in OUTPUT chain: %s", err)
|
| 62 | 62 |
} |
| 63 | 63 |
return chain, nil |
| ... | ... |
@@ -78,7 +79,7 @@ func (c *Chain) Forward(action Action, ip net.IP, port int, proto, dest_addr str |
| 78 | 78 |
// value" by both iptables and ip6tables. |
| 79 | 79 |
daddr = "0/0" |
| 80 | 80 |
} |
| 81 |
- if output, err := Raw("-t", "nat", fmt.Sprint(action), c.Name,
|
|
| 81 |
+ if output, err := Raw("-t", "nat", string(action), c.Name,
|
|
| 82 | 82 |
"-p", proto, |
| 83 | 83 |
"-d", daddr, |
| 84 | 84 |
"--dport", strconv.Itoa(port), |
| ... | ... |
@@ -90,11 +91,13 @@ func (c *Chain) Forward(action Action, ip net.IP, port int, proto, dest_addr str |
| 90 | 90 |
return &ChainError{Chain: "FORWARD", Output: output}
|
| 91 | 91 |
} |
| 92 | 92 |
|
| 93 |
- fAction := action |
|
| 94 |
- if fAction == Add {
|
|
| 95 |
- fAction = "-I" |
|
| 93 |
+ if action != Delete {
|
|
| 94 |
+ if err := c.createForwardChain(); err != nil {
|
|
| 95 |
+ return err |
|
| 96 |
+ } |
|
| 96 | 97 |
} |
| 97 |
- if output, err := Raw(string(fAction), "FORWARD", |
|
| 98 |
+ |
|
| 99 |
+ if output, err := Raw(string(action), c.Name, |
|
| 98 | 100 |
"!", "-i", c.Bridge, |
| 99 | 101 |
"-o", c.Bridge, |
| 100 | 102 |
"-p", proto, |
| ... | ... |
@@ -109,6 +112,39 @@ func (c *Chain) Forward(action Action, ip net.IP, port int, proto, dest_addr str |
| 109 | 109 |
return nil |
| 110 | 110 |
} |
| 111 | 111 |
|
| 112 |
+func (c *Chain) Link(action Action, ip1, ip2 net.IP, port int, proto string) error {
|
|
| 113 |
+ if action != Delete {
|
|
| 114 |
+ if err := c.createForwardChain(); err != nil {
|
|
| 115 |
+ return err |
|
| 116 |
+ } |
|
| 117 |
+ } |
|
| 118 |
+ if output, err := Raw(string(action), c.Name, |
|
| 119 |
+ "-i", c.Bridge, "-o", c.Bridge, |
|
| 120 |
+ "-p", proto, |
|
| 121 |
+ "-s", ip1.String(), |
|
| 122 |
+ "--dport", strconv.Itoa(port), |
|
| 123 |
+ "-d", ip2.String(), |
|
| 124 |
+ "-j", "ACCEPT"); err != nil {
|
|
| 125 |
+ return err |
|
| 126 |
+ } else if len(output) != 0 {
|
|
| 127 |
+ return fmt.Errorf("Error toggle iptables forward: %s", output)
|
|
| 128 |
+ } |
|
| 129 |
+ |
|
| 130 |
+ if output, err := Raw(string(action), c.Name, |
|
| 131 |
+ "-i", c.Bridge, "-o", c.Bridge, |
|
| 132 |
+ "-p", proto, |
|
| 133 |
+ "-s", ip2.String(), |
|
| 134 |
+ "--dport", strconv.Itoa(port), |
|
| 135 |
+ "-d", ip1.String(), |
|
| 136 |
+ "-j", "ACCEPT"); err != nil {
|
|
| 137 |
+ return err |
|
| 138 |
+ } else if len(output) != 0 {
|
|
| 139 |
+ return fmt.Errorf("Error toggle iptables forward: %s", output)
|
|
| 140 |
+ } |
|
| 141 |
+ |
|
| 142 |
+ return nil |
|
| 143 |
+} |
|
| 144 |
+ |
|
| 112 | 145 |
func (c *Chain) Prerouting(action Action, args ...string) error {
|
| 113 | 146 |
a := append(nat, fmt.Sprint(action), "PREROUTING") |
| 114 | 147 |
if len(args) > 0 {
|
| ... | ... |
@@ -199,3 +235,28 @@ func Raw(args ...string) ([]byte, error) {
|
| 199 | 199 |
|
| 200 | 200 |
return output, err |
| 201 | 201 |
} |
| 202 |
+ |
|
| 203 |
+func (c *Chain) createForwardChain() error {
|
|
| 204 |
+ // Add chain if doesn't exist |
|
| 205 |
+ if _, err := Raw("-n", "-L", c.Name); err != nil {
|
|
| 206 |
+ output, err := Raw("-N", c.Name)
|
|
| 207 |
+ if err != nil {
|
|
| 208 |
+ return err |
|
| 209 |
+ } else if len(output) != 0 {
|
|
| 210 |
+ return fmt.Errorf("Error iptables forward: %s", output)
|
|
| 211 |
+ } |
|
| 212 |
+ } |
|
| 213 |
+ // Add linking rule if it doesn't exist |
|
| 214 |
+ if !Exists("FORWARD",
|
|
| 215 |
+ "-o", c.Bridge, |
|
| 216 |
+ "-j", c.Name) {
|
|
| 217 |
+ if output2, err := Raw(string(Insert), "FORWARD", |
|
| 218 |
+ "-o", c.Bridge, |
|
| 219 |
+ "-j", c.Name); err != nil {
|
|
| 220 |
+ return err |
|
| 221 |
+ } else if len(output2) != 0 {
|
|
| 222 |
+ return fmt.Errorf("Error iptables forward: %s", output2)
|
|
| 223 |
+ } |
|
| 224 |
+ } |
|
| 225 |
+ return nil |
|
| 226 |
+} |