github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edgemesh/pkg/proxy/proxy.go (about) 1 package proxy 2 3 import ( 4 "bufio" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "strings" 9 "time" 10 11 "github.com/vishvananda/netlink" 12 "k8s.io/klog" 13 utiliptables "k8s.io/kubernetes/pkg/util/iptables" 14 utilexec "k8s.io/utils/exec" 15 16 "github.com/kubeedge/kubeedge/edgemesh/pkg/config" 17 ) 18 19 // iptables rules 20 type Proxier struct { 21 iptables utiliptables.Interface 22 inboundRule string 23 outboundRule string 24 dNatRule string 25 } 26 27 const ( 28 meshChain = "EDGE-MESH" 29 hostResolv = "/etc/resolv.conf" 30 ) 31 32 var ( 33 proxier *Proxier 34 route netlink.Route 35 ) 36 37 func Init() { 38 protocol := utiliptables.ProtocolIpv4 39 exec := utilexec.New() 40 iptInterface := utiliptables.New(exec, protocol) 41 proxier = &Proxier{ 42 iptables: iptInterface, 43 inboundRule: "-p tcp -d " + config.Config.SubNet + " -i " + config.Config.ListenInterface + " -j " + meshChain, 44 outboundRule: "-p tcp -d " + config.Config.SubNet + " -o " + config.Config.ListenInterface + " -j " + meshChain, 45 dNatRule: "-p tcp -j DNAT --to-destination " + config.Config.Listener.Addr().String(), 46 } 47 // read and clean iptables rules 48 proxier.readAndCleanRule() 49 // ensure iptables rules 50 proxier.ensureRule() 51 // add route 52 dst, err := netlink.ParseIPNet(config.Config.SubNet) 53 if err != nil { 54 klog.Errorf("[EdgeMesh] parse subnet error: %v", err) 55 return 56 } 57 gw := config.Config.ListenIP 58 route = netlink.Route{ 59 Dst: dst, 60 Gw: gw, 61 } 62 err = netlink.RouteAdd(&route) 63 if err != nil { 64 klog.Warningf("[EdgeMesh] add route err: %v", err) 65 } 66 // save iptables rules 67 proxier.saveRule() 68 // ensure resolv.conf 69 ensureResolvForHost() 70 // sync 71 go proxier.sync() 72 } 73 74 // sync periodically 75 func (p *Proxier) sync() { 76 syncRuleTicker := time.NewTicker(10 * time.Second) 77 for { 78 <-syncRuleTicker.C 79 p.ensureRule() 80 ensureResolvForHost() 81 } 82 } 83 84 // ensureRule ensures iptables rules exist 85 func (p *Proxier) ensureRule() { 86 iptInterface := p.iptables 87 inboundRule := strings.Split(p.inboundRule, " ") 88 outboundRule := strings.Split(p.outboundRule, " ") 89 dNatRule := strings.Split(p.dNatRule, " ") 90 exist, err := iptInterface.EnsureChain(utiliptables.TableNAT, meshChain) 91 if err != nil { 92 klog.Errorf("[EdgeMesh] ensure chain %s failed with err: %v", meshChain, err) 93 } 94 if !exist { 95 klog.Infof("[EdgeMesh] chain %s not exists", meshChain) 96 } 97 98 exist, err = iptInterface.EnsureRule(utiliptables.Append, utiliptables.TableNAT, utiliptables.ChainPrerouting, inboundRule...) 99 if err != nil { 100 klog.Errorf("[EdgeMesh] ensure inbound rule %s failed with err: %v", p.inboundRule, err) 101 } 102 if !exist { 103 klog.Infof("[EdgeMesh] inbound rule %s not exists", p.inboundRule) 104 } 105 106 exist, err = iptInterface.EnsureRule(utiliptables.Append, utiliptables.TableNAT, utiliptables.ChainOutput, outboundRule...) 107 if err != nil { 108 klog.Errorf("[EdgeMesh] ensure outbound rule %s failed with err: %v", p.outboundRule, err) 109 } 110 if !exist { 111 klog.Infof("[EdgeMesh] outbound rule %s not exists", p.outboundRule) 112 } 113 114 exist, err = iptInterface.EnsureRule(utiliptables.Append, utiliptables.TableNAT, meshChain, dNatRule...) 115 if err != nil { 116 klog.Errorf("[EdgeMesh] ensure dnat rule %s failed with err: %v", p.dNatRule, err) 117 } 118 if !exist { 119 klog.Infof("[EdgeMesh] dnat rule %s not exists", p.dNatRule) 120 } 121 } 122 123 // saveRule saves iptables rules into file 124 func (p *Proxier) saveRule() { 125 file, err := os.OpenFile("/run/edgemesh-iptables", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) 126 if err != nil { 127 klog.Errorf("[EdgeMesh] open file /run/edgemesh-iptables err: %v", err) 128 return 129 } 130 // store 131 defer file.Close() 132 w := bufio.NewWriter(file) 133 fmt.Fprintln(w, p.inboundRule) 134 fmt.Fprintln(w, p.dNatRule) 135 fmt.Fprintln(w, p.outboundRule) 136 w.Flush() 137 } 138 139 // readAndCleanRule reads iptables rules from file and cleans them 140 func (p *Proxier) readAndCleanRule() { 141 file, err := os.OpenFile("/run/edgemesh-iptables", os.O_RDONLY, 0444) 142 if err != nil { 143 klog.Errorf("[EdgeMesh] open file /run/edgemesh-iptables err: %v", err) 144 return 145 } 146 147 defer file.Close() 148 scan := bufio.NewScanner(file) 149 scan.Split(bufio.ScanLines) 150 for scan.Scan() { 151 serverString := scan.Text() 152 if strings.Contains(serverString, "-o") { 153 p.iptables.DeleteRule(utiliptables.TableNAT, utiliptables.ChainOutput, strings.Split(serverString, " ")...) 154 } else if strings.Contains(serverString, "-i") { 155 p.iptables.DeleteRule(utiliptables.TableNAT, utiliptables.ChainPrerouting, strings.Split(serverString, " ")...) 156 } 157 } 158 p.iptables.FlushChain(utiliptables.TableNAT, meshChain) 159 p.iptables.DeleteChain(utiliptables.TableNAT, meshChain) 160 } 161 162 // ensureResolvForHost adds edgemesh dns server to the head of /etc/resolv.conf 163 func ensureResolvForHost() { 164 bs, err := ioutil.ReadFile(hostResolv) 165 if err != nil { 166 klog.Errorf("[EdgeMesh] read file %s err: %v", hostResolv, err) 167 return 168 } 169 170 resolv := strings.Split(string(bs), "\n") 171 if resolv == nil { 172 nameserver := "nameserver " + config.Config.ListenIP.String() 173 ioutil.WriteFile(hostResolv, []byte(nameserver), 0600) 174 return 175 } 176 177 configured := false 178 dnsIdx := 0 179 startIdx := 0 180 for idx, item := range resolv { 181 if strings.Contains(item, config.Config.ListenIP.String()) { 182 configured = true 183 dnsIdx = idx 184 break 185 } 186 } 187 for idx, item := range resolv { 188 if strings.Contains(item, "nameserver") { 189 startIdx = idx 190 break 191 } 192 } 193 if configured { 194 if dnsIdx != startIdx && dnsIdx > startIdx { 195 nameserver := sortNameserver(resolv, dnsIdx, startIdx) 196 ioutil.WriteFile(hostResolv, []byte(nameserver), 0600) 197 } 198 return 199 } 200 201 nameserver := "" 202 for idx := 0; idx < len(resolv); { 203 if idx == startIdx { 204 startIdx = -1 205 nameserver = nameserver + "nameserver " + config.Config.ListenIP.String() + "\n" 206 continue 207 } 208 nameserver = nameserver + resolv[idx] + "\n" 209 idx++ 210 } 211 212 ioutil.WriteFile(hostResolv, []byte(nameserver), 0600) 213 } 214 215 func sortNameserver(resolv []string, dnsIdx, startIdx int) string { 216 nameserver := "" 217 idx := 0 218 for ; idx < startIdx; idx++ { 219 nameserver = nameserver + resolv[idx] + "\n" 220 } 221 nameserver = nameserver + resolv[dnsIdx] + "\n" 222 223 for idx = startIdx; idx < len(resolv); idx++ { 224 if idx == dnsIdx { 225 continue 226 } 227 nameserver = nameserver + resolv[idx] + "\n" 228 } 229 230 return nameserver 231 } 232 233 func Clean() { 234 proxier.readAndCleanRule() 235 netlink.RouteDel(&route) 236 bs, err := ioutil.ReadFile(hostResolv) 237 if err != nil { 238 klog.Warningf("[EdgeMesh] read file %s err: %v", hostResolv, err) 239 } 240 241 resolv := strings.Split(string(bs), "\n") 242 if resolv == nil { 243 return 244 } 245 nameserver := "" 246 for _, item := range resolv { 247 if strings.Contains(item, config.Config.ListenIP.String()) { 248 continue 249 } 250 nameserver = nameserver + item + "\n" 251 } 252 ioutil.WriteFile(hostResolv, []byte(nameserver), 0600) 253 }