github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/networking/portfwd.go (about) 1 // Copyright 2015 The rkt Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package networking 16 17 import ( 18 "fmt" 19 "net" 20 "strconv" 21 22 "github.com/coreos/go-iptables/iptables" 23 ) 24 25 func (e *podEnv) forwardPorts(fps []ForwardedPort, defIP net.IP) error { 26 if len(fps) == 0 { 27 return nil 28 } 29 30 ipt, err := iptables.New() 31 if err != nil { 32 return err 33 } 34 35 // Create a separate chain for this pod. This helps with debugging 36 // and makes it easier to cleanup 37 chainDNAT := e.portFwdChain("DNAT") 38 chainSNAT := e.portFwdChain("SNAT") 39 40 if err = ipt.NewChain("nat", chainDNAT); err != nil { 41 return err 42 } 43 44 if err = ipt.NewChain("nat", chainSNAT); err != nil { 45 return err 46 } 47 48 chainRuleDNAT := e.portFwdChainRuleSpec(chainDNAT, "DNAT") 49 chainRuleSNAT := e.portFwdChainRuleSpec(chainSNAT, "SNAT") 50 51 for _, entry := range []struct { 52 chain string 53 customChainRule []string 54 }{ 55 {"POSTROUTING", chainRuleSNAT}, // traffic originating from this host 56 {"PREROUTING", chainRuleDNAT}, // outside traffic hitting this host 57 {"OUTPUT", chainRuleDNAT}, // traffic originating from this host 58 } { 59 exists, err := ipt.Exists("nat", entry.chain, entry.customChainRule...) 60 if err != nil { 61 return err 62 } 63 if !exists { 64 err = ipt.Insert("nat", entry.chain, 1, entry.customChainRule...) 65 if err != nil { 66 return err 67 } 68 } 69 } 70 71 for _, p := range fps { 72 73 dst := fmt.Sprintf("%v:%v", defIP, p.PodPort) 74 dstIP := fmt.Sprintf("%v", defIP) 75 dport := strconv.Itoa(int(p.HostPort)) 76 77 for _, r := range []struct { 78 chain string 79 rule []string 80 }{ 81 { // Rewrite the destination 82 chainDNAT, 83 []string{ 84 "-p", p.Protocol, 85 "--dport", dport, 86 "-j", "DNAT", 87 "--to-destination", dst, 88 }, 89 }, 90 { // Rewrite the source for connections to localhost on the host 91 chainSNAT, 92 []string{ 93 "-p", p.Protocol, 94 "-s", "127.0.0.1", 95 "-d", dstIP, 96 "--dport", dport, 97 "-j", "MASQUERADE", 98 }, 99 }, 100 } { 101 if err := ipt.AppendUnique("nat", r.chain, r.rule...); err != nil { 102 return err 103 } 104 } 105 } 106 return nil 107 } 108 109 func (e *podEnv) unforwardPorts() error { 110 ipt, err := iptables.New() 111 if err != nil { 112 return err 113 } 114 115 chainDNAT := e.portFwdChain("DNAT") 116 chainSNAT := e.portFwdChain("SNAT") 117 118 chainRuleDNAT := e.portFwdChainRuleSpec(chainDNAT, "DNAT") 119 chainRuleSNAT := e.portFwdChainRuleSpec(chainSNAT, "SNAT") 120 121 // There's no clean way now to test if a chain exists or 122 // even if a rule exists if the chain is not present. 123 // So we swallow the errors for now :( 124 // TODO(eyakubovich): move to using libiptc for iptable 125 // manipulation 126 127 for _, entry := range []struct { 128 chain string 129 customChainRule []string 130 }{ 131 {"POSTROUTING", chainRuleSNAT}, // traffic originating on this host 132 {"PREROUTING", chainRuleDNAT}, // outside traffic hitting this host 133 {"OUTPUT", chainRuleDNAT}, // traffic originating on this host 134 } { 135 ipt.Delete("nat", entry.chain, entry.customChainRule...) 136 } 137 138 for _, entry := range []string{chainDNAT, chainSNAT} { 139 ipt.ClearChain("nat", entry) 140 ipt.DeleteChain("nat", entry) 141 } 142 return nil 143 } 144 145 func (e *podEnv) portFwdChain(name string) string { 146 return fmt.Sprintf("RKT-PFWD-%s-%s", name, e.podID.String()[0:8]) 147 } 148 149 func (e *podEnv) portFwdChainRuleSpec(chain string, name string) []string { 150 switch name { 151 case "SNAT": 152 return []string{"-s", "127.0.0.1", "!", "-d", "127.0.0.1", "-j", chain} 153 case "DNAT": 154 return []string{"-m", "addrtype", "--dst-type", "LOCAL", "-j", chain} 155 default: 156 return nil 157 } 158 }