proxier.go 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503
  1. /*
  2. Copyright 2015 The Kubernetes Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package iptables
  14. //
  15. // NOTE: this needs to be tested in e2e since it uses iptables for everything.
  16. //
  17. import (
  18. "bytes"
  19. "crypto/sha256"
  20. "encoding/base32"
  21. "fmt"
  22. "net"
  23. "strconv"
  24. "strings"
  25. "sync"
  26. "sync/atomic"
  27. "time"
  28. "k8s.io/klog"
  29. v1 "k8s.io/api/core/v1"
  30. "k8s.io/apimachinery/pkg/types"
  31. utilversion "k8s.io/apimachinery/pkg/util/version"
  32. "k8s.io/apimachinery/pkg/util/wait"
  33. "k8s.io/client-go/tools/record"
  34. "k8s.io/kubernetes/pkg/proxy"
  35. "k8s.io/kubernetes/pkg/proxy/healthcheck"
  36. "k8s.io/kubernetes/pkg/proxy/metrics"
  37. utilproxy "k8s.io/kubernetes/pkg/proxy/util"
  38. "k8s.io/kubernetes/pkg/util/async"
  39. "k8s.io/kubernetes/pkg/util/conntrack"
  40. utiliptables "k8s.io/kubernetes/pkg/util/iptables"
  41. utilsysctl "k8s.io/kubernetes/pkg/util/sysctl"
  42. utilexec "k8s.io/utils/exec"
  43. utilnet "k8s.io/utils/net"
  44. )
  45. const (
  46. // iptablesMinVersion is the minimum version of iptables for which we will use the Proxier
  47. // from this package instead of the userspace Proxier. While most of the
  48. // features we need were available earlier, the '-C' flag was added more
  49. // recently. We use that indirectly in Ensure* functions, and if we don't
  50. // have it, we have to be extra careful about the exact args we feed in being
  51. // the same as the args we read back (iptables itself normalizes some args).
  52. // This is the "new" Proxier, so we require "new" versions of tools.
  53. iptablesMinVersion = utiliptables.MinCheckVersion
  54. // the services chain
  55. kubeServicesChain utiliptables.Chain = "KUBE-SERVICES"
  56. // the external services chain
  57. kubeExternalServicesChain utiliptables.Chain = "KUBE-EXTERNAL-SERVICES"
  58. // the nodeports chain
  59. kubeNodePortsChain utiliptables.Chain = "KUBE-NODEPORTS"
  60. // the kubernetes postrouting chain
  61. kubePostroutingChain utiliptables.Chain = "KUBE-POSTROUTING"
  62. // KubeMarkMasqChain is the mark-for-masquerade chain
  63. KubeMarkMasqChain utiliptables.Chain = "KUBE-MARK-MASQ"
  64. // KubeMarkDropChain is the mark-for-drop chain
  65. KubeMarkDropChain utiliptables.Chain = "KUBE-MARK-DROP"
  66. // the kubernetes forward chain
  67. kubeForwardChain utiliptables.Chain = "KUBE-FORWARD"
  68. )
  69. // Versioner can query the current iptables version.
  70. type Versioner interface {
  71. // returns "X.Y.Z"
  72. GetVersion() (string, error)
  73. }
  74. // KernelCompatTester tests whether the required kernel capabilities are
  75. // present to run the iptables proxier.
  76. type KernelCompatTester interface {
  77. IsCompatible() error
  78. }
  79. // CanUseIPTablesProxier returns true if we should use the iptables Proxier
  80. // instead of the "classic" userspace Proxier. This is determined by checking
  81. // the iptables version and for the existence of kernel features. It may return
  82. // an error if it fails to get the iptables version without error, in which
  83. // case it will also return false.
  84. func CanUseIPTablesProxier(iptver Versioner, kcompat KernelCompatTester) (bool, error) {
  85. minVersion, err := utilversion.ParseGeneric(iptablesMinVersion)
  86. if err != nil {
  87. return false, err
  88. }
  89. versionString, err := iptver.GetVersion()
  90. if err != nil {
  91. return false, err
  92. }
  93. version, err := utilversion.ParseGeneric(versionString)
  94. if err != nil {
  95. return false, err
  96. }
  97. if version.LessThan(minVersion) {
  98. return false, nil
  99. }
  100. // Check that the kernel supports what we need.
  101. if err := kcompat.IsCompatible(); err != nil {
  102. return false, err
  103. }
  104. return true, nil
  105. }
  106. // LinuxKernelCompatTester is the Linux implementation of KernelCompatTester
  107. type LinuxKernelCompatTester struct{}
  108. // IsCompatible checks for the required sysctls. We don't care about the value, just
  109. // that it exists. If this Proxier is chosen, we'll initialize it as we
  110. // need.
  111. func (lkct LinuxKernelCompatTester) IsCompatible() error {
  112. _, err := utilsysctl.New().GetSysctl(sysctlRouteLocalnet)
  113. return err
  114. }
  115. const sysctlRouteLocalnet = "net/ipv4/conf/all/route_localnet"
  116. const sysctlBridgeCallIPTables = "net/bridge/bridge-nf-call-iptables"
  117. // internal struct for string service information
  118. type serviceInfo struct {
  119. *proxy.BaseServiceInfo
  120. // The following fields are computed and stored for performance reasons.
  121. serviceNameString string
  122. servicePortChainName utiliptables.Chain
  123. serviceFirewallChainName utiliptables.Chain
  124. serviceLBChainName utiliptables.Chain
  125. }
  126. // returns a new proxy.ServicePort which abstracts a serviceInfo
  127. func newServiceInfo(port *v1.ServicePort, service *v1.Service, baseInfo *proxy.BaseServiceInfo) proxy.ServicePort {
  128. info := &serviceInfo{BaseServiceInfo: baseInfo}
  129. // Store the following for performance reasons.
  130. svcName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name}
  131. svcPortName := proxy.ServicePortName{NamespacedName: svcName, Port: port.Name}
  132. protocol := strings.ToLower(string(info.Protocol))
  133. info.serviceNameString = svcPortName.String()
  134. info.servicePortChainName = servicePortChainName(info.serviceNameString, protocol)
  135. info.serviceFirewallChainName = serviceFirewallChainName(info.serviceNameString, protocol)
  136. info.serviceLBChainName = serviceLBChainName(info.serviceNameString, protocol)
  137. return info
  138. }
  139. // internal struct for endpoints information
  140. type endpointsInfo struct {
  141. *proxy.BaseEndpointInfo
  142. // The following fields we lazily compute and store here for performance
  143. // reasons. If the protocol is the same as you expect it to be, then the
  144. // chainName can be reused, otherwise it should be recomputed.
  145. protocol string
  146. chainName utiliptables.Chain
  147. }
  148. // returns a new proxy.Endpoint which abstracts a endpointsInfo
  149. func newEndpointInfo(baseInfo *proxy.BaseEndpointInfo) proxy.Endpoint {
  150. return &endpointsInfo{BaseEndpointInfo: baseInfo}
  151. }
  152. // Equal overrides the Equal() function implemented by proxy.BaseEndpointInfo.
  153. func (e *endpointsInfo) Equal(other proxy.Endpoint) bool {
  154. o, ok := other.(*endpointsInfo)
  155. if !ok {
  156. klog.Error("Failed to cast endpointsInfo")
  157. return false
  158. }
  159. return e.Endpoint == o.Endpoint &&
  160. e.IsLocal == o.IsLocal &&
  161. e.protocol == o.protocol &&
  162. e.chainName == o.chainName
  163. }
  164. // Returns the endpoint chain name for a given endpointsInfo.
  165. func (e *endpointsInfo) endpointChain(svcNameString, protocol string) utiliptables.Chain {
  166. if e.protocol != protocol {
  167. e.protocol = protocol
  168. e.chainName = servicePortEndpointChainName(svcNameString, protocol, e.Endpoint)
  169. }
  170. return e.chainName
  171. }
  172. // Proxier is an iptables based proxy for connections between a localhost:lport
  173. // and services that provide the actual backends.
  174. type Proxier struct {
  175. // endpointsChanges and serviceChanges contains all changes to endpoints and
  176. // services that happened since iptables was synced. For a single object,
  177. // changes are accumulated, i.e. previous is state from before all of them,
  178. // current is state after applying all of those.
  179. endpointsChanges *proxy.EndpointChangeTracker
  180. serviceChanges *proxy.ServiceChangeTracker
  181. mu sync.Mutex // protects the following fields
  182. serviceMap proxy.ServiceMap
  183. endpointsMap proxy.EndpointsMap
  184. portsMap map[utilproxy.LocalPort]utilproxy.Closeable
  185. // endpointsSynced and servicesSynced are set to true when corresponding
  186. // objects are synced after startup. This is used to avoid updating iptables
  187. // with some partial data after kube-proxy restart.
  188. endpointsSynced bool
  189. servicesSynced bool
  190. initialized int32
  191. syncRunner *async.BoundedFrequencyRunner // governs calls to syncProxyRules
  192. // These are effectively const and do not need the mutex to be held.
  193. iptables utiliptables.Interface
  194. masqueradeAll bool
  195. masqueradeMark string
  196. exec utilexec.Interface
  197. clusterCIDR string
  198. hostname string
  199. nodeIP net.IP
  200. portMapper utilproxy.PortOpener
  201. recorder record.EventRecorder
  202. healthChecker healthcheck.Server
  203. healthzServer healthcheck.HealthzUpdater
  204. // Since converting probabilities (floats) to strings is expensive
  205. // and we are using only probabilities in the format of 1/n, we are
  206. // precomputing some number of those and cache for future reuse.
  207. precomputedProbabilities []string
  208. // The following buffers are used to reuse memory and avoid allocations
  209. // that are significantly impacting performance.
  210. iptablesData *bytes.Buffer
  211. existingFilterChainsData *bytes.Buffer
  212. filterChains *bytes.Buffer
  213. filterRules *bytes.Buffer
  214. natChains *bytes.Buffer
  215. natRules *bytes.Buffer
  216. // endpointChainsNumber is the total amount of endpointChains across all
  217. // services that we will generate (it is computed at the beginning of
  218. // syncProxyRules method). If that is large enough, comments in some
  219. // iptable rules are dropped to improve performance.
  220. endpointChainsNumber int
  221. // Values are as a parameter to select the interfaces where nodeport works.
  222. nodePortAddresses []string
  223. // networkInterfacer defines an interface for several net library functions.
  224. // Inject for test purpose.
  225. networkInterfacer utilproxy.NetworkInterfacer
  226. }
  227. // listenPortOpener opens ports by calling bind() and listen().
  228. type listenPortOpener struct{}
  229. // OpenLocalPort holds the given local port open.
  230. func (l *listenPortOpener) OpenLocalPort(lp *utilproxy.LocalPort) (utilproxy.Closeable, error) {
  231. return openLocalPort(lp)
  232. }
  233. // Proxier implements ProxyProvider
  234. var _ proxy.ProxyProvider = &Proxier{}
  235. // NewProxier returns a new Proxier given an iptables Interface instance.
  236. // Because of the iptables logic, it is assumed that there is only a single Proxier active on a machine.
  237. // An error will be returned if iptables fails to update or acquire the initial lock.
  238. // Once a proxier is created, it will keep iptables up to date in the background and
  239. // will not terminate if a particular iptables call fails.
  240. func NewProxier(ipt utiliptables.Interface,
  241. sysctl utilsysctl.Interface,
  242. exec utilexec.Interface,
  243. syncPeriod time.Duration,
  244. minSyncPeriod time.Duration,
  245. masqueradeAll bool,
  246. masqueradeBit int,
  247. clusterCIDR string,
  248. hostname string,
  249. nodeIP net.IP,
  250. recorder record.EventRecorder,
  251. healthzServer healthcheck.HealthzUpdater,
  252. nodePortAddresses []string,
  253. ) (*Proxier, error) {
  254. // Set the route_localnet sysctl we need for
  255. if val, _ := sysctl.GetSysctl(sysctlRouteLocalnet); val != 1 {
  256. if err := sysctl.SetSysctl(sysctlRouteLocalnet, 1); err != nil {
  257. return nil, fmt.Errorf("can't set sysctl %s: %v", sysctlRouteLocalnet, err)
  258. }
  259. }
  260. // Proxy needs br_netfilter and bridge-nf-call-iptables=1 when containers
  261. // are connected to a Linux bridge (but not SDN bridges). Until most
  262. // plugins handle this, log when config is missing
  263. if val, err := sysctl.GetSysctl(sysctlBridgeCallIPTables); err == nil && val != 1 {
  264. klog.Warning("missing br-netfilter module or unset sysctl br-nf-call-iptables; proxy may not work as intended")
  265. }
  266. // Generate the masquerade mark to use for SNAT rules.
  267. masqueradeValue := 1 << uint(masqueradeBit)
  268. masqueradeMark := fmt.Sprintf("%#08x/%#08x", masqueradeValue, masqueradeValue)
  269. if nodeIP == nil {
  270. klog.Warning("invalid nodeIP, initializing kube-proxy with 127.0.0.1 as nodeIP")
  271. nodeIP = net.ParseIP("127.0.0.1")
  272. }
  273. if len(clusterCIDR) == 0 {
  274. klog.Warning("clusterCIDR not specified, unable to distinguish between internal and external traffic")
  275. } else if utilnet.IsIPv6CIDRString(clusterCIDR) != ipt.IsIpv6() {
  276. return nil, fmt.Errorf("clusterCIDR %s has incorrect IP version: expect isIPv6=%t", clusterCIDR, ipt.IsIpv6())
  277. }
  278. healthChecker := healthcheck.NewServer(hostname, recorder, nil, nil) // use default implementations of deps
  279. isIPv6 := ipt.IsIpv6()
  280. proxier := &Proxier{
  281. portsMap: make(map[utilproxy.LocalPort]utilproxy.Closeable),
  282. serviceMap: make(proxy.ServiceMap),
  283. serviceChanges: proxy.NewServiceChangeTracker(newServiceInfo, &isIPv6, recorder),
  284. endpointsMap: make(proxy.EndpointsMap),
  285. endpointsChanges: proxy.NewEndpointChangeTracker(hostname, newEndpointInfo, &isIPv6, recorder),
  286. iptables: ipt,
  287. masqueradeAll: masqueradeAll,
  288. masqueradeMark: masqueradeMark,
  289. exec: exec,
  290. clusterCIDR: clusterCIDR,
  291. hostname: hostname,
  292. nodeIP: nodeIP,
  293. portMapper: &listenPortOpener{},
  294. recorder: recorder,
  295. healthChecker: healthChecker,
  296. healthzServer: healthzServer,
  297. precomputedProbabilities: make([]string, 0, 1001),
  298. iptablesData: bytes.NewBuffer(nil),
  299. existingFilterChainsData: bytes.NewBuffer(nil),
  300. filterChains: bytes.NewBuffer(nil),
  301. filterRules: bytes.NewBuffer(nil),
  302. natChains: bytes.NewBuffer(nil),
  303. natRules: bytes.NewBuffer(nil),
  304. nodePortAddresses: nodePortAddresses,
  305. networkInterfacer: utilproxy.RealNetwork{},
  306. }
  307. burstSyncs := 2
  308. klog.V(3).Infof("minSyncPeriod: %v, syncPeriod: %v, burstSyncs: %d", minSyncPeriod, syncPeriod, burstSyncs)
  309. proxier.syncRunner = async.NewBoundedFrequencyRunner("sync-runner", proxier.syncProxyRules, minSyncPeriod, syncPeriod, burstSyncs)
  310. return proxier, nil
  311. }
  312. type iptablesJumpChain struct {
  313. table utiliptables.Table
  314. dstChain utiliptables.Chain
  315. srcChain utiliptables.Chain
  316. comment string
  317. extraArgs []string
  318. }
  319. var iptablesJumpChains = []iptablesJumpChain{
  320. {utiliptables.TableFilter, kubeExternalServicesChain, utiliptables.ChainInput, "kubernetes externally-visible service portals", []string{"-m", "conntrack", "--ctstate", "NEW"}},
  321. {utiliptables.TableFilter, kubeServicesChain, utiliptables.ChainForward, "kubernetes service portals", []string{"-m", "conntrack", "--ctstate", "NEW"}},
  322. {utiliptables.TableFilter, kubeServicesChain, utiliptables.ChainOutput, "kubernetes service portals", []string{"-m", "conntrack", "--ctstate", "NEW"}},
  323. {utiliptables.TableFilter, kubeServicesChain, utiliptables.ChainInput, "kubernetes service portals", []string{"-m", "conntrack", "--ctstate", "NEW"}},
  324. {utiliptables.TableFilter, kubeForwardChain, utiliptables.ChainForward, "kubernetes forwarding rules", nil},
  325. {utiliptables.TableNAT, kubeServicesChain, utiliptables.ChainOutput, "kubernetes service portals", nil},
  326. {utiliptables.TableNAT, kubeServicesChain, utiliptables.ChainPrerouting, "kubernetes service portals", nil},
  327. {utiliptables.TableNAT, kubePostroutingChain, utiliptables.ChainPostrouting, "kubernetes postrouting rules", nil},
  328. }
  329. var iptablesCleanupOnlyChains = []iptablesJumpChain{}
  330. // CleanupLeftovers removes all iptables rules and chains created by the Proxier
  331. // It returns true if an error was encountered. Errors are logged.
  332. func CleanupLeftovers(ipt utiliptables.Interface) (encounteredError bool) {
  333. // Unlink our chains
  334. for _, jump := range append(iptablesJumpChains, iptablesCleanupOnlyChains...) {
  335. args := append(jump.extraArgs,
  336. "-m", "comment", "--comment", jump.comment,
  337. "-j", string(jump.dstChain),
  338. )
  339. if err := ipt.DeleteRule(jump.table, jump.srcChain, args...); err != nil {
  340. if !utiliptables.IsNotFoundError(err) {
  341. klog.Errorf("Error removing pure-iptables proxy rule: %v", err)
  342. encounteredError = true
  343. }
  344. }
  345. }
  346. // Flush and remove all of our "-t nat" chains.
  347. iptablesData := bytes.NewBuffer(nil)
  348. if err := ipt.SaveInto(utiliptables.TableNAT, iptablesData); err != nil {
  349. klog.Errorf("Failed to execute iptables-save for %s: %v", utiliptables.TableNAT, err)
  350. encounteredError = true
  351. } else {
  352. existingNATChains := utiliptables.GetChainLines(utiliptables.TableNAT, iptablesData.Bytes())
  353. natChains := bytes.NewBuffer(nil)
  354. natRules := bytes.NewBuffer(nil)
  355. writeLine(natChains, "*nat")
  356. // Start with chains we know we need to remove.
  357. for _, chain := range []utiliptables.Chain{kubeServicesChain, kubeNodePortsChain, kubePostroutingChain, KubeMarkMasqChain} {
  358. if _, found := existingNATChains[chain]; found {
  359. chainString := string(chain)
  360. writeBytesLine(natChains, existingNATChains[chain]) // flush
  361. writeLine(natRules, "-X", chainString) // delete
  362. }
  363. }
  364. // Hunt for service and endpoint chains.
  365. for chain := range existingNATChains {
  366. chainString := string(chain)
  367. if strings.HasPrefix(chainString, "KUBE-SVC-") || strings.HasPrefix(chainString, "KUBE-SEP-") || strings.HasPrefix(chainString, "KUBE-FW-") || strings.HasPrefix(chainString, "KUBE-XLB-") {
  368. writeBytesLine(natChains, existingNATChains[chain]) // flush
  369. writeLine(natRules, "-X", chainString) // delete
  370. }
  371. }
  372. writeLine(natRules, "COMMIT")
  373. natLines := append(natChains.Bytes(), natRules.Bytes()...)
  374. // Write it.
  375. err = ipt.Restore(utiliptables.TableNAT, natLines, utiliptables.NoFlushTables, utiliptables.RestoreCounters)
  376. if err != nil {
  377. klog.Errorf("Failed to execute iptables-restore for %s: %v", utiliptables.TableNAT, err)
  378. encounteredError = true
  379. }
  380. }
  381. // Flush and remove all of our "-t filter" chains.
  382. iptablesData.Reset()
  383. if err := ipt.SaveInto(utiliptables.TableFilter, iptablesData); err != nil {
  384. klog.Errorf("Failed to execute iptables-save for %s: %v", utiliptables.TableFilter, err)
  385. encounteredError = true
  386. } else {
  387. existingFilterChains := utiliptables.GetChainLines(utiliptables.TableFilter, iptablesData.Bytes())
  388. filterChains := bytes.NewBuffer(nil)
  389. filterRules := bytes.NewBuffer(nil)
  390. writeLine(filterChains, "*filter")
  391. for _, chain := range []utiliptables.Chain{kubeServicesChain, kubeExternalServicesChain, kubeForwardChain} {
  392. if _, found := existingFilterChains[chain]; found {
  393. chainString := string(chain)
  394. writeBytesLine(filterChains, existingFilterChains[chain])
  395. writeLine(filterRules, "-X", chainString)
  396. }
  397. }
  398. writeLine(filterRules, "COMMIT")
  399. filterLines := append(filterChains.Bytes(), filterRules.Bytes()...)
  400. // Write it.
  401. if err := ipt.Restore(utiliptables.TableFilter, filterLines, utiliptables.NoFlushTables, utiliptables.RestoreCounters); err != nil {
  402. klog.Errorf("Failed to execute iptables-restore for %s: %v", utiliptables.TableFilter, err)
  403. encounteredError = true
  404. }
  405. }
  406. return encounteredError
  407. }
  408. func computeProbability(n int) string {
  409. return fmt.Sprintf("%0.5f", 1.0/float64(n))
  410. }
  411. // This assumes proxier.mu is held
  412. func (proxier *Proxier) precomputeProbabilities(numberOfPrecomputed int) {
  413. if len(proxier.precomputedProbabilities) == 0 {
  414. proxier.precomputedProbabilities = append(proxier.precomputedProbabilities, "<bad value>")
  415. }
  416. for i := len(proxier.precomputedProbabilities); i <= numberOfPrecomputed; i++ {
  417. proxier.precomputedProbabilities = append(proxier.precomputedProbabilities, computeProbability(i))
  418. }
  419. }
  420. // This assumes proxier.mu is held
  421. func (proxier *Proxier) probability(n int) string {
  422. if n >= len(proxier.precomputedProbabilities) {
  423. proxier.precomputeProbabilities(n)
  424. }
  425. return proxier.precomputedProbabilities[n]
  426. }
  427. // Sync is called to synchronize the proxier state to iptables as soon as possible.
  428. func (proxier *Proxier) Sync() {
  429. proxier.syncRunner.Run()
  430. }
  431. // SyncLoop runs periodic work. This is expected to run as a goroutine or as the main loop of the app. It does not return.
  432. func (proxier *Proxier) SyncLoop() {
  433. // Update healthz timestamp at beginning in case Sync() never succeeds.
  434. if proxier.healthzServer != nil {
  435. proxier.healthzServer.UpdateTimestamp()
  436. }
  437. proxier.syncRunner.Loop(wait.NeverStop)
  438. }
  439. func (proxier *Proxier) setInitialized(value bool) {
  440. var initialized int32
  441. if value {
  442. initialized = 1
  443. }
  444. atomic.StoreInt32(&proxier.initialized, initialized)
  445. }
  446. func (proxier *Proxier) isInitialized() bool {
  447. return atomic.LoadInt32(&proxier.initialized) > 0
  448. }
  449. // OnServiceAdd is called whenever creation of new service object
  450. // is observed.
  451. func (proxier *Proxier) OnServiceAdd(service *v1.Service) {
  452. proxier.OnServiceUpdate(nil, service)
  453. }
  454. // OnServiceUpdate is called whenever modification of an existing
  455. // service object is observed.
  456. func (proxier *Proxier) OnServiceUpdate(oldService, service *v1.Service) {
  457. if proxier.serviceChanges.Update(oldService, service) && proxier.isInitialized() {
  458. proxier.syncRunner.Run()
  459. }
  460. }
  461. // OnServiceDelete is called whenever deletion of an existing service
  462. // object is observed.
  463. func (proxier *Proxier) OnServiceDelete(service *v1.Service) {
  464. proxier.OnServiceUpdate(service, nil)
  465. }
  466. // OnServiceSynced is called once all the initial even handlers were
  467. // called and the state is fully propagated to local cache.
  468. func (proxier *Proxier) OnServiceSynced() {
  469. proxier.mu.Lock()
  470. proxier.servicesSynced = true
  471. proxier.setInitialized(proxier.servicesSynced && proxier.endpointsSynced)
  472. proxier.mu.Unlock()
  473. // Sync unconditionally - this is called once per lifetime.
  474. proxier.syncProxyRules()
  475. }
  476. // OnEndpointsAdd is called whenever creation of new endpoints object
  477. // is observed.
  478. func (proxier *Proxier) OnEndpointsAdd(endpoints *v1.Endpoints) {
  479. proxier.OnEndpointsUpdate(nil, endpoints)
  480. }
  481. // OnEndpointsUpdate is called whenever modification of an existing
  482. // endpoints object is observed.
  483. func (proxier *Proxier) OnEndpointsUpdate(oldEndpoints, endpoints *v1.Endpoints) {
  484. if proxier.endpointsChanges.Update(oldEndpoints, endpoints) && proxier.isInitialized() {
  485. proxier.syncRunner.Run()
  486. }
  487. }
  488. // OnEndpointsDelete is called whever deletion of an existing endpoints
  489. // object is observed.
  490. func (proxier *Proxier) OnEndpointsDelete(endpoints *v1.Endpoints) {
  491. proxier.OnEndpointsUpdate(endpoints, nil)
  492. }
  493. // OnEndpointsSynced is called once all the initial event handlers were
  494. // called and the state is fully propagated to local cache.
  495. func (proxier *Proxier) OnEndpointsSynced() {
  496. proxier.mu.Lock()
  497. proxier.endpointsSynced = true
  498. proxier.setInitialized(proxier.servicesSynced && proxier.endpointsSynced)
  499. proxier.mu.Unlock()
  500. // Sync unconditionally - this is called once per lifetime.
  501. proxier.syncProxyRules()
  502. }
  503. // portProtoHash takes the ServicePortName and protocol for a service
  504. // returns the associated 16 character hash. This is computed by hashing (sha256)
  505. // then encoding to base32 and truncating to 16 chars. We do this because IPTables
  506. // Chain Names must be <= 28 chars long, and the longer they are the harder they are to read.
  507. func portProtoHash(servicePortName string, protocol string) string {
  508. hash := sha256.Sum256([]byte(servicePortName + protocol))
  509. encoded := base32.StdEncoding.EncodeToString(hash[:])
  510. return encoded[:16]
  511. }
  512. // servicePortChainName takes the ServicePortName for a service and
  513. // returns the associated iptables chain. This is computed by hashing (sha256)
  514. // then encoding to base32 and truncating with the prefix "KUBE-SVC-".
  515. func servicePortChainName(servicePortName string, protocol string) utiliptables.Chain {
  516. return utiliptables.Chain("KUBE-SVC-" + portProtoHash(servicePortName, protocol))
  517. }
  518. // serviceFirewallChainName takes the ServicePortName for a service and
  519. // returns the associated iptables chain. This is computed by hashing (sha256)
  520. // then encoding to base32 and truncating with the prefix "KUBE-FW-".
  521. func serviceFirewallChainName(servicePortName string, protocol string) utiliptables.Chain {
  522. return utiliptables.Chain("KUBE-FW-" + portProtoHash(servicePortName, protocol))
  523. }
  524. // serviceLBPortChainName takes the ServicePortName for a service and
  525. // returns the associated iptables chain. This is computed by hashing (sha256)
  526. // then encoding to base32 and truncating with the prefix "KUBE-XLB-". We do
  527. // this because IPTables Chain Names must be <= 28 chars long, and the longer
  528. // they are the harder they are to read.
  529. func serviceLBChainName(servicePortName string, protocol string) utiliptables.Chain {
  530. return utiliptables.Chain("KUBE-XLB-" + portProtoHash(servicePortName, protocol))
  531. }
  532. // This is the same as servicePortChainName but with the endpoint included.
  533. func servicePortEndpointChainName(servicePortName string, protocol string, endpoint string) utiliptables.Chain {
  534. hash := sha256.Sum256([]byte(servicePortName + protocol + endpoint))
  535. encoded := base32.StdEncoding.EncodeToString(hash[:])
  536. return utiliptables.Chain("KUBE-SEP-" + encoded[:16])
  537. }
  538. // After a UDP endpoint has been removed, we must flush any pending conntrack entries to it, or else we
  539. // risk sending more traffic to it, all of which will be lost (because UDP).
  540. // This assumes the proxier mutex is held
  541. // TODO: move it to util
  542. func (proxier *Proxier) deleteEndpointConnections(connectionMap []proxy.ServiceEndpoint) {
  543. for _, epSvcPair := range connectionMap {
  544. if svcInfo, ok := proxier.serviceMap[epSvcPair.ServicePortName]; ok && svcInfo.GetProtocol() == v1.ProtocolUDP {
  545. endpointIP := utilproxy.IPPart(epSvcPair.Endpoint)
  546. nodePort := svcInfo.GetNodePort()
  547. var err error
  548. if nodePort != 0 {
  549. err = conntrack.ClearEntriesForPortNAT(proxier.exec, endpointIP, nodePort, v1.ProtocolUDP)
  550. } else {
  551. err = conntrack.ClearEntriesForNAT(proxier.exec, svcInfo.ClusterIPString(), endpointIP, v1.ProtocolUDP)
  552. }
  553. if err != nil {
  554. klog.Errorf("Failed to delete %s endpoint connections, error: %v", epSvcPair.ServicePortName.String(), err)
  555. }
  556. for _, extIP := range svcInfo.ExternalIPStrings() {
  557. err := conntrack.ClearEntriesForNAT(proxier.exec, extIP, endpointIP, v1.ProtocolUDP)
  558. if err != nil {
  559. klog.Errorf("Failed to delete %s endpoint connections for externalIP %s, error: %v", epSvcPair.ServicePortName.String(), extIP, err)
  560. }
  561. }
  562. for _, lbIP := range svcInfo.LoadBalancerIPStrings() {
  563. err := conntrack.ClearEntriesForNAT(proxier.exec, lbIP, endpointIP, v1.ProtocolUDP)
  564. if err != nil {
  565. klog.Errorf("Failed to delete %s endpoint connections for LoabBalancerIP %s, error: %v", epSvcPair.ServicePortName.String(), lbIP, err)
  566. }
  567. }
  568. }
  569. }
  570. }
  571. const endpointChainsNumberThreshold = 1000
  572. // Assumes proxier.mu is held.
  573. func (proxier *Proxier) appendServiceCommentLocked(args []string, svcName string) {
  574. // Not printing these comments, can reduce size of iptables (in case of large
  575. // number of endpoints) even by 40%+. So if total number of endpoint chains
  576. // is large enough, we simply drop those comments.
  577. if proxier.endpointChainsNumber > endpointChainsNumberThreshold {
  578. return
  579. }
  580. args = append(args, "-m", "comment", "--comment", svcName)
  581. }
  582. // This is where all of the iptables-save/restore calls happen.
  583. // The only other iptables rules are those that are setup in iptablesInit()
  584. // This assumes proxier.mu is NOT held
  585. func (proxier *Proxier) syncProxyRules() {
  586. proxier.mu.Lock()
  587. defer proxier.mu.Unlock()
  588. start := time.Now()
  589. defer func() {
  590. metrics.SyncProxyRulesLatency.Observe(metrics.SinceInSeconds(start))
  591. metrics.DeprecatedSyncProxyRulesLatency.Observe(metrics.SinceInMicroseconds(start))
  592. klog.V(4).Infof("syncProxyRules took %v", time.Since(start))
  593. }()
  594. // don't sync rules till we've received services and endpoints
  595. if !proxier.endpointsSynced || !proxier.servicesSynced {
  596. klog.V(2).Info("Not syncing iptables until Services and Endpoints have been received from master")
  597. return
  598. }
  599. // We assume that if this was called, we really want to sync them,
  600. // even if nothing changed in the meantime. In other words, callers are
  601. // responsible for detecting no-op changes and not calling this function.
  602. serviceUpdateResult := proxy.UpdateServiceMap(proxier.serviceMap, proxier.serviceChanges)
  603. endpointUpdateResult := proxier.endpointsMap.Update(proxier.endpointsChanges)
  604. staleServices := serviceUpdateResult.UDPStaleClusterIP
  605. // merge stale services gathered from updateEndpointsMap
  606. for _, svcPortName := range endpointUpdateResult.StaleServiceNames {
  607. if svcInfo, ok := proxier.serviceMap[svcPortName]; ok && svcInfo != nil && svcInfo.GetProtocol() == v1.ProtocolUDP {
  608. klog.V(2).Infof("Stale udp service %v -> %s", svcPortName, svcInfo.ClusterIPString())
  609. staleServices.Insert(svcInfo.ClusterIPString())
  610. for _, extIP := range svcInfo.ExternalIPStrings() {
  611. staleServices.Insert(extIP)
  612. }
  613. }
  614. }
  615. klog.V(3).Info("Syncing iptables rules")
  616. // Create and link the kube chains.
  617. for _, jump := range iptablesJumpChains {
  618. if _, err := proxier.iptables.EnsureChain(jump.table, jump.dstChain); err != nil {
  619. klog.Errorf("Failed to ensure that %s chain %s exists: %v", jump.table, jump.dstChain, err)
  620. return
  621. }
  622. args := append(jump.extraArgs,
  623. "-m", "comment", "--comment", jump.comment,
  624. "-j", string(jump.dstChain),
  625. )
  626. if _, err := proxier.iptables.EnsureRule(utiliptables.Prepend, jump.table, jump.srcChain, args...); err != nil {
  627. klog.Errorf("Failed to ensure that %s chain %s jumps to %s: %v", jump.table, jump.srcChain, jump.dstChain, err)
  628. return
  629. }
  630. }
  631. //
  632. // Below this point we will not return until we try to write the iptables rules.
  633. //
  634. // Get iptables-save output so we can check for existing chains and rules.
  635. // This will be a map of chain name to chain with rules as stored in iptables-save/iptables-restore
  636. existingFilterChains := make(map[utiliptables.Chain][]byte)
  637. proxier.existingFilterChainsData.Reset()
  638. err := proxier.iptables.SaveInto(utiliptables.TableFilter, proxier.existingFilterChainsData)
  639. if err != nil { // if we failed to get any rules
  640. klog.Errorf("Failed to execute iptables-save, syncing all rules: %v", err)
  641. } else { // otherwise parse the output
  642. existingFilterChains = utiliptables.GetChainLines(utiliptables.TableFilter, proxier.existingFilterChainsData.Bytes())
  643. }
  644. // IMPORTANT: existingNATChains may share memory with proxier.iptablesData.
  645. existingNATChains := make(map[utiliptables.Chain][]byte)
  646. proxier.iptablesData.Reset()
  647. err = proxier.iptables.SaveInto(utiliptables.TableNAT, proxier.iptablesData)
  648. if err != nil { // if we failed to get any rules
  649. klog.Errorf("Failed to execute iptables-save, syncing all rules: %v", err)
  650. } else { // otherwise parse the output
  651. existingNATChains = utiliptables.GetChainLines(utiliptables.TableNAT, proxier.iptablesData.Bytes())
  652. }
  653. // Reset all buffers used later.
  654. // This is to avoid memory reallocations and thus improve performance.
  655. proxier.filterChains.Reset()
  656. proxier.filterRules.Reset()
  657. proxier.natChains.Reset()
  658. proxier.natRules.Reset()
  659. // Write table headers.
  660. writeLine(proxier.filterChains, "*filter")
  661. writeLine(proxier.natChains, "*nat")
  662. // Make sure we keep stats for the top-level chains, if they existed
  663. // (which most should have because we created them above).
  664. for _, chainName := range []utiliptables.Chain{kubeServicesChain, kubeExternalServicesChain, kubeForwardChain} {
  665. if chain, ok := existingFilterChains[chainName]; ok {
  666. writeBytesLine(proxier.filterChains, chain)
  667. } else {
  668. writeLine(proxier.filterChains, utiliptables.MakeChainLine(chainName))
  669. }
  670. }
  671. for _, chainName := range []utiliptables.Chain{kubeServicesChain, kubeNodePortsChain, kubePostroutingChain, KubeMarkMasqChain} {
  672. if chain, ok := existingNATChains[chainName]; ok {
  673. writeBytesLine(proxier.natChains, chain)
  674. } else {
  675. writeLine(proxier.natChains, utiliptables.MakeChainLine(chainName))
  676. }
  677. }
  678. // Install the kubernetes-specific postrouting rules. We use a whole chain for
  679. // this so that it is easier to flush and change, for example if the mark
  680. // value should ever change.
  681. writeLine(proxier.natRules, []string{
  682. "-A", string(kubePostroutingChain),
  683. "-m", "comment", "--comment", `"kubernetes service traffic requiring SNAT"`,
  684. "-m", "mark", "--mark", proxier.masqueradeMark,
  685. "-j", "MASQUERADE",
  686. }...)
  687. // Install the kubernetes-specific masquerade mark rule. We use a whole chain for
  688. // this so that it is easier to flush and change, for example if the mark
  689. // value should ever change.
  690. writeLine(proxier.natRules, []string{
  691. "-A", string(KubeMarkMasqChain),
  692. "-j", "MARK", "--set-xmark", proxier.masqueradeMark,
  693. }...)
  694. // Accumulate NAT chains to keep.
  695. activeNATChains := map[utiliptables.Chain]bool{} // use a map as a set
  696. // Accumulate the set of local ports that we will be holding open once this update is complete
  697. replacementPortsMap := map[utilproxy.LocalPort]utilproxy.Closeable{}
  698. // We are creating those slices ones here to avoid memory reallocations
  699. // in every loop. Note that reuse the memory, instead of doing:
  700. // slice = <some new slice>
  701. // you should always do one of the below:
  702. // slice = slice[:0] // and then append to it
  703. // slice = append(slice[:0], ...)
  704. endpoints := make([]*endpointsInfo, 0)
  705. endpointChains := make([]utiliptables.Chain, 0)
  706. // To avoid growing this slice, we arbitrarily set its size to 64,
  707. // there is never more than that many arguments for a single line.
  708. // Note that even if we go over 64, it will still be correct - it
  709. // is just for efficiency, not correctness.
  710. args := make([]string, 64)
  711. // Compute total number of endpoint chains across all services.
  712. proxier.endpointChainsNumber = 0
  713. for svcName := range proxier.serviceMap {
  714. proxier.endpointChainsNumber += len(proxier.endpointsMap[svcName])
  715. }
  716. // Build rules for each service.
  717. for svcName, svc := range proxier.serviceMap {
  718. svcInfo, ok := svc.(*serviceInfo)
  719. if !ok {
  720. klog.Errorf("Failed to cast serviceInfo %q", svcName.String())
  721. continue
  722. }
  723. isIPv6 := utilnet.IsIPv6(svcInfo.ClusterIP)
  724. protocol := strings.ToLower(string(svcInfo.Protocol))
  725. svcNameString := svcInfo.serviceNameString
  726. hasEndpoints := len(proxier.endpointsMap[svcName]) > 0
  727. svcChain := svcInfo.servicePortChainName
  728. if hasEndpoints {
  729. // Create the per-service chain, retaining counters if possible.
  730. if chain, ok := existingNATChains[svcChain]; ok {
  731. writeBytesLine(proxier.natChains, chain)
  732. } else {
  733. writeLine(proxier.natChains, utiliptables.MakeChainLine(svcChain))
  734. }
  735. activeNATChains[svcChain] = true
  736. }
  737. svcXlbChain := svcInfo.serviceLBChainName
  738. if svcInfo.OnlyNodeLocalEndpoints {
  739. // Only for services request OnlyLocal traffic
  740. // create the per-service LB chain, retaining counters if possible.
  741. if lbChain, ok := existingNATChains[svcXlbChain]; ok {
  742. writeBytesLine(proxier.natChains, lbChain)
  743. } else {
  744. writeLine(proxier.natChains, utiliptables.MakeChainLine(svcXlbChain))
  745. }
  746. activeNATChains[svcXlbChain] = true
  747. }
  748. // Capture the clusterIP.
  749. if hasEndpoints {
  750. args = append(args[:0],
  751. "-A", string(kubeServicesChain),
  752. "-m", "comment", "--comment", fmt.Sprintf(`"%s cluster IP"`, svcNameString),
  753. "-m", protocol, "-p", protocol,
  754. "-d", utilproxy.ToCIDR(svcInfo.ClusterIP),
  755. "--dport", strconv.Itoa(svcInfo.Port),
  756. )
  757. if proxier.masqueradeAll {
  758. writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...)
  759. } else if len(proxier.clusterCIDR) > 0 {
  760. // This masquerades off-cluster traffic to a service VIP. The idea
  761. // is that you can establish a static route for your Service range,
  762. // routing to any node, and that node will bridge into the Service
  763. // for you. Since that might bounce off-node, we masquerade here.
  764. // If/when we support "Local" policy for VIPs, we should update this.
  765. writeLine(proxier.natRules, append(args, "! -s", proxier.clusterCIDR, "-j", string(KubeMarkMasqChain))...)
  766. }
  767. writeLine(proxier.natRules, append(args, "-j", string(svcChain))...)
  768. } else {
  769. // No endpoints.
  770. writeLine(proxier.filterRules,
  771. "-A", string(kubeServicesChain),
  772. "-m", "comment", "--comment", fmt.Sprintf(`"%s has no endpoints"`, svcNameString),
  773. "-m", protocol, "-p", protocol,
  774. "-d", utilproxy.ToCIDR(svcInfo.ClusterIP),
  775. "--dport", strconv.Itoa(svcInfo.Port),
  776. "-j", "REJECT",
  777. )
  778. }
  779. // Capture externalIPs.
  780. for _, externalIP := range svcInfo.ExternalIPs {
  781. // If the "external" IP happens to be an IP that is local to this
  782. // machine, hold the local port open so no other process can open it
  783. // (because the socket might open but it would never work).
  784. if local, err := utilproxy.IsLocalIP(externalIP); err != nil {
  785. klog.Errorf("can't determine if IP is local, assuming not: %v", err)
  786. } else if local && (svcInfo.GetProtocol() != v1.ProtocolSCTP) {
  787. lp := utilproxy.LocalPort{
  788. Description: "externalIP for " + svcNameString,
  789. IP: externalIP,
  790. Port: svcInfo.Port,
  791. Protocol: protocol,
  792. }
  793. if proxier.portsMap[lp] != nil {
  794. klog.V(4).Infof("Port %s was open before and is still needed", lp.String())
  795. replacementPortsMap[lp] = proxier.portsMap[lp]
  796. } else {
  797. socket, err := proxier.portMapper.OpenLocalPort(&lp)
  798. if err != nil {
  799. msg := fmt.Sprintf("can't open %s, skipping this externalIP: %v", lp.String(), err)
  800. proxier.recorder.Eventf(
  801. &v1.ObjectReference{
  802. Kind: "Node",
  803. Name: proxier.hostname,
  804. UID: types.UID(proxier.hostname),
  805. Namespace: "",
  806. }, v1.EventTypeWarning, err.Error(), msg)
  807. klog.Error(msg)
  808. continue
  809. }
  810. replacementPortsMap[lp] = socket
  811. }
  812. }
  813. if hasEndpoints {
  814. args = append(args[:0],
  815. "-A", string(kubeServicesChain),
  816. "-m", "comment", "--comment", fmt.Sprintf(`"%s external IP"`, svcNameString),
  817. "-m", protocol, "-p", protocol,
  818. "-d", utilproxy.ToCIDR(net.ParseIP(externalIP)),
  819. "--dport", strconv.Itoa(svcInfo.Port),
  820. )
  821. // We have to SNAT packets to external IPs.
  822. writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...)
  823. // Allow traffic for external IPs that does not come from a bridge (i.e. not from a container)
  824. // nor from a local process to be forwarded to the service.
  825. // This rule roughly translates to "all traffic from off-machine".
  826. // This is imperfect in the face of network plugins that might not use a bridge, but we can revisit that later.
  827. externalTrafficOnlyArgs := append(args,
  828. "-m", "physdev", "!", "--physdev-is-in",
  829. "-m", "addrtype", "!", "--src-type", "LOCAL")
  830. writeLine(proxier.natRules, append(externalTrafficOnlyArgs, "-j", string(svcChain))...)
  831. dstLocalOnlyArgs := append(args, "-m", "addrtype", "--dst-type", "LOCAL")
  832. // Allow traffic bound for external IPs that happen to be recognized as local IPs to stay local.
  833. // This covers cases like GCE load-balancers which get added to the local routing table.
  834. writeLine(proxier.natRules, append(dstLocalOnlyArgs, "-j", string(svcChain))...)
  835. } else {
  836. // No endpoints.
  837. writeLine(proxier.filterRules,
  838. "-A", string(kubeExternalServicesChain),
  839. "-m", "comment", "--comment", fmt.Sprintf(`"%s has no endpoints"`, svcNameString),
  840. "-m", protocol, "-p", protocol,
  841. "-d", utilproxy.ToCIDR(net.ParseIP(externalIP)),
  842. "--dport", strconv.Itoa(svcInfo.Port),
  843. "-j", "REJECT",
  844. )
  845. }
  846. }
  847. // Capture load-balancer ingress.
  848. fwChain := svcInfo.serviceFirewallChainName
  849. for _, ingress := range svcInfo.LoadBalancerStatus.Ingress {
  850. if ingress.IP != "" {
  851. if hasEndpoints {
  852. // create service firewall chain
  853. if chain, ok := existingNATChains[fwChain]; ok {
  854. writeBytesLine(proxier.natChains, chain)
  855. } else {
  856. writeLine(proxier.natChains, utiliptables.MakeChainLine(fwChain))
  857. }
  858. activeNATChains[fwChain] = true
  859. // The service firewall rules are created based on ServiceSpec.loadBalancerSourceRanges field.
  860. // This currently works for loadbalancers that preserves source ips.
  861. // For loadbalancers which direct traffic to service NodePort, the firewall rules will not apply.
  862. args = append(args[:0],
  863. "-A", string(kubeServicesChain),
  864. "-m", "comment", "--comment", fmt.Sprintf(`"%s loadbalancer IP"`, svcNameString),
  865. "-m", protocol, "-p", protocol,
  866. "-d", utilproxy.ToCIDR(net.ParseIP(ingress.IP)),
  867. "--dport", strconv.Itoa(svcInfo.Port),
  868. )
  869. // jump to service firewall chain
  870. writeLine(proxier.natRules, append(args, "-j", string(fwChain))...)
  871. args = append(args[:0],
  872. "-A", string(fwChain),
  873. "-m", "comment", "--comment", fmt.Sprintf(`"%s loadbalancer IP"`, svcNameString),
  874. )
  875. // Each source match rule in the FW chain may jump to either the SVC or the XLB chain
  876. chosenChain := svcXlbChain
  877. // If we are proxying globally, we need to masquerade in case we cross nodes.
  878. // If we are proxying only locally, we can retain the source IP.
  879. if !svcInfo.OnlyNodeLocalEndpoints {
  880. writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...)
  881. chosenChain = svcChain
  882. }
  883. if len(svcInfo.LoadBalancerSourceRanges) == 0 {
  884. // allow all sources, so jump directly to the KUBE-SVC or KUBE-XLB chain
  885. writeLine(proxier.natRules, append(args, "-j", string(chosenChain))...)
  886. } else {
  887. // firewall filter based on each source range
  888. allowFromNode := false
  889. for _, src := range svcInfo.LoadBalancerSourceRanges {
  890. writeLine(proxier.natRules, append(args, "-s", src, "-j", string(chosenChain))...)
  891. // ignore error because it has been validated
  892. _, cidr, _ := net.ParseCIDR(src)
  893. if cidr.Contains(proxier.nodeIP) {
  894. allowFromNode = true
  895. }
  896. }
  897. // generally, ip route rule was added to intercept request to loadbalancer vip from the
  898. // loadbalancer's backend hosts. In this case, request will not hit the loadbalancer but loop back directly.
  899. // Need to add the following rule to allow request on host.
  900. if allowFromNode {
  901. writeLine(proxier.natRules, append(args, "-s", utilproxy.ToCIDR(net.ParseIP(ingress.IP)), "-j", string(chosenChain))...)
  902. }
  903. }
  904. // If the packet was able to reach the end of firewall chain, then it did not get DNATed.
  905. // It means the packet cannot go thru the firewall, then mark it for DROP
  906. writeLine(proxier.natRules, append(args, "-j", string(KubeMarkDropChain))...)
  907. } else {
  908. // No endpoints.
  909. writeLine(proxier.filterRules,
  910. "-A", string(kubeServicesChain),
  911. "-m", "comment", "--comment", fmt.Sprintf(`"%s has no endpoints"`, svcNameString),
  912. "-m", protocol, "-p", protocol,
  913. "-d", utilproxy.ToCIDR(net.ParseIP(ingress.IP)),
  914. "--dport", strconv.Itoa(svcInfo.Port),
  915. "-j", "REJECT",
  916. )
  917. }
  918. }
  919. }
  920. // Capture nodeports. If we had more than 2 rules it might be
  921. // worthwhile to make a new per-service chain for nodeport rules, but
  922. // with just 2 rules it ends up being a waste and a cognitive burden.
  923. if svcInfo.NodePort != 0 {
  924. // Hold the local port open so no other process can open it
  925. // (because the socket might open but it would never work).
  926. addresses, err := utilproxy.GetNodeAddresses(proxier.nodePortAddresses, proxier.networkInterfacer)
  927. if err != nil {
  928. klog.Errorf("Failed to get node ip address matching nodeport cidr: %v", err)
  929. continue
  930. }
  931. lps := make([]utilproxy.LocalPort, 0)
  932. for address := range addresses {
  933. lp := utilproxy.LocalPort{
  934. Description: "nodePort for " + svcNameString,
  935. IP: address,
  936. Port: svcInfo.NodePort,
  937. Protocol: protocol,
  938. }
  939. if utilproxy.IsZeroCIDR(address) {
  940. // Empty IP address means all
  941. lp.IP = ""
  942. lps = append(lps, lp)
  943. // If we encounter a zero CIDR, then there is no point in processing the rest of the addresses.
  944. break
  945. }
  946. lps = append(lps, lp)
  947. }
  948. // For ports on node IPs, open the actual port and hold it.
  949. for _, lp := range lps {
  950. if proxier.portsMap[lp] != nil {
  951. klog.V(4).Infof("Port %s was open before and is still needed", lp.String())
  952. replacementPortsMap[lp] = proxier.portsMap[lp]
  953. } else if svcInfo.GetProtocol() != v1.ProtocolSCTP {
  954. socket, err := proxier.portMapper.OpenLocalPort(&lp)
  955. if err != nil {
  956. klog.Errorf("can't open %s, skipping this nodePort: %v", lp.String(), err)
  957. continue
  958. }
  959. if lp.Protocol == "udp" {
  960. // TODO: We might have multiple services using the same port, and this will clear conntrack for all of them.
  961. // This is very low impact. The NodePort range is intentionally obscure, and unlikely to actually collide with real Services.
  962. // This only affects UDP connections, which are not common.
  963. // See issue: https://github.com/kubernetes/kubernetes/issues/49881
  964. err := conntrack.ClearEntriesForPort(proxier.exec, lp.Port, isIPv6, v1.ProtocolUDP)
  965. if err != nil {
  966. klog.Errorf("Failed to clear udp conntrack for port %d, error: %v", lp.Port, err)
  967. }
  968. }
  969. replacementPortsMap[lp] = socket
  970. }
  971. }
  972. if hasEndpoints {
  973. args = append(args[:0],
  974. "-A", string(kubeNodePortsChain),
  975. "-m", "comment", "--comment", svcNameString,
  976. "-m", protocol, "-p", protocol,
  977. "--dport", strconv.Itoa(svcInfo.NodePort),
  978. )
  979. if !svcInfo.OnlyNodeLocalEndpoints {
  980. // Nodeports need SNAT, unless they're local.
  981. writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...)
  982. // Jump to the service chain.
  983. writeLine(proxier.natRules, append(args, "-j", string(svcChain))...)
  984. } else {
  985. // TODO: Make all nodePorts jump to the firewall chain.
  986. // Currently we only create it for loadbalancers (#33586).
  987. // Fix localhost martian source error
  988. loopback := "127.0.0.0/8"
  989. if isIPv6 {
  990. loopback = "::1/128"
  991. }
  992. writeLine(proxier.natRules, append(args, "-s", loopback, "-j", string(KubeMarkMasqChain))...)
  993. writeLine(proxier.natRules, append(args, "-j", string(svcXlbChain))...)
  994. }
  995. } else {
  996. // No endpoints.
  997. writeLine(proxier.filterRules,
  998. "-A", string(kubeExternalServicesChain),
  999. "-m", "comment", "--comment", fmt.Sprintf(`"%s has no endpoints"`, svcNameString),
  1000. "-m", "addrtype", "--dst-type", "LOCAL",
  1001. "-m", protocol, "-p", protocol,
  1002. "--dport", strconv.Itoa(svcInfo.NodePort),
  1003. "-j", "REJECT",
  1004. )
  1005. }
  1006. }
  1007. if !hasEndpoints {
  1008. continue
  1009. }
  1010. // Generate the per-endpoint chains. We do this in multiple passes so we
  1011. // can group rules together.
  1012. // These two slices parallel each other - keep in sync
  1013. endpoints = endpoints[:0]
  1014. endpointChains = endpointChains[:0]
  1015. var endpointChain utiliptables.Chain
  1016. for _, ep := range proxier.endpointsMap[svcName] {
  1017. epInfo, ok := ep.(*endpointsInfo)
  1018. if !ok {
  1019. klog.Errorf("Failed to cast endpointsInfo %q", ep.String())
  1020. continue
  1021. }
  1022. endpoints = append(endpoints, epInfo)
  1023. endpointChain = epInfo.endpointChain(svcNameString, protocol)
  1024. endpointChains = append(endpointChains, endpointChain)
  1025. // Create the endpoint chain, retaining counters if possible.
  1026. if chain, ok := existingNATChains[utiliptables.Chain(endpointChain)]; ok {
  1027. writeBytesLine(proxier.natChains, chain)
  1028. } else {
  1029. writeLine(proxier.natChains, utiliptables.MakeChainLine(endpointChain))
  1030. }
  1031. activeNATChains[endpointChain] = true
  1032. }
  1033. // First write session affinity rules, if applicable.
  1034. if svcInfo.SessionAffinityType == v1.ServiceAffinityClientIP {
  1035. for _, endpointChain := range endpointChains {
  1036. args = append(args[:0],
  1037. "-A", string(svcChain),
  1038. )
  1039. proxier.appendServiceCommentLocked(args, svcNameString)
  1040. args = append(args,
  1041. "-m", "recent", "--name", string(endpointChain),
  1042. "--rcheck", "--seconds", strconv.Itoa(svcInfo.StickyMaxAgeSeconds), "--reap",
  1043. "-j", string(endpointChain),
  1044. )
  1045. writeLine(proxier.natRules, args...)
  1046. }
  1047. }
  1048. // Now write loadbalancing & DNAT rules.
  1049. n := len(endpointChains)
  1050. localEndpoints := make([]*endpointsInfo, 0)
  1051. localEndpointChains := make([]utiliptables.Chain, 0)
  1052. for i, endpointChain := range endpointChains {
  1053. // Write ingress loadbalancing & DNAT rules only for services that request OnlyLocal traffic.
  1054. if svcInfo.OnlyNodeLocalEndpoints && endpoints[i].IsLocal {
  1055. // These slices parallel each other; must be kept in sync
  1056. localEndpoints = append(localEndpoints, endpoints[i])
  1057. localEndpointChains = append(localEndpointChains, endpointChains[i])
  1058. }
  1059. epIP := endpoints[i].IP()
  1060. if epIP == "" {
  1061. // Error parsing this endpoint has been logged. Skip to next endpoint.
  1062. continue
  1063. }
  1064. // Balancing rules in the per-service chain.
  1065. args = append(args[:0], "-A", string(svcChain))
  1066. proxier.appendServiceCommentLocked(args, svcNameString)
  1067. if i < (n - 1) {
  1068. // Each rule is a probabilistic match.
  1069. args = append(args,
  1070. "-m", "statistic",
  1071. "--mode", "random",
  1072. "--probability", proxier.probability(n-i))
  1073. }
  1074. // The final (or only if n == 1) rule is a guaranteed match.
  1075. args = append(args, "-j", string(endpointChain))
  1076. writeLine(proxier.natRules, args...)
  1077. // Rules in the per-endpoint chain.
  1078. args = append(args[:0], "-A", string(endpointChain))
  1079. proxier.appendServiceCommentLocked(args, svcNameString)
  1080. // Handle traffic that loops back to the originator with SNAT.
  1081. writeLine(proxier.natRules, append(args,
  1082. "-s", utilproxy.ToCIDR(net.ParseIP(epIP)),
  1083. "-j", string(KubeMarkMasqChain))...)
  1084. // Update client-affinity lists.
  1085. if svcInfo.SessionAffinityType == v1.ServiceAffinityClientIP {
  1086. args = append(args, "-m", "recent", "--name", string(endpointChain), "--set")
  1087. }
  1088. // DNAT to final destination.
  1089. args = append(args, "-m", protocol, "-p", protocol, "-j", "DNAT", "--to-destination", endpoints[i].Endpoint)
  1090. writeLine(proxier.natRules, args...)
  1091. }
  1092. // The logic below this applies only if this service is marked as OnlyLocal
  1093. if !svcInfo.OnlyNodeLocalEndpoints {
  1094. continue
  1095. }
  1096. // For LBs with externalTrafficPolicy=Local, we need to re-route any local traffic to the service chain masqueraded.
  1097. // Masqueraded traffic in this scenario is okay since source IP preservation only applies to external traffic anyways.
  1098. args = append(args[:0], "-A", string(svcXlbChain))
  1099. writeLine(proxier.natRules, append(args,
  1100. "-m", "comment", "--comment", fmt.Sprintf(`"masquerade LOCAL traffic for %s LB IP"`, svcNameString),
  1101. "-m", "addrtype", "--src-type", "LOCAL", "-j", string(KubeMarkMasqChain))...)
  1102. writeLine(proxier.natRules, append(args,
  1103. "-m", "comment", "--comment", fmt.Sprintf(`"route LOCAL traffic for %s LB IP to service chain"`, svcNameString),
  1104. "-m", "addrtype", "--src-type", "LOCAL", "-j", string(svcChain))...)
  1105. // First rule in the chain redirects all pod -> external VIP traffic to the
  1106. // Service's ClusterIP instead. This happens whether or not we have local
  1107. // endpoints; only if clusterCIDR is specified
  1108. if len(proxier.clusterCIDR) > 0 {
  1109. args = append(args[:0],
  1110. "-A", string(svcXlbChain),
  1111. "-m", "comment", "--comment",
  1112. `"Redirect pods trying to reach external loadbalancer VIP to clusterIP"`,
  1113. "-s", proxier.clusterCIDR,
  1114. "-j", string(svcChain),
  1115. )
  1116. writeLine(proxier.natRules, args...)
  1117. }
  1118. numLocalEndpoints := len(localEndpointChains)
  1119. if numLocalEndpoints == 0 {
  1120. // Blackhole all traffic since there are no local endpoints
  1121. args = append(args[:0],
  1122. "-A", string(svcXlbChain),
  1123. "-m", "comment", "--comment",
  1124. fmt.Sprintf(`"%s has no local endpoints"`, svcNameString),
  1125. "-j",
  1126. string(KubeMarkDropChain),
  1127. )
  1128. writeLine(proxier.natRules, args...)
  1129. } else {
  1130. // First write session affinity rules only over local endpoints, if applicable.
  1131. if svcInfo.SessionAffinityType == v1.ServiceAffinityClientIP {
  1132. for _, endpointChain := range localEndpointChains {
  1133. writeLine(proxier.natRules,
  1134. "-A", string(svcXlbChain),
  1135. "-m", "comment", "--comment", svcNameString,
  1136. "-m", "recent", "--name", string(endpointChain),
  1137. "--rcheck", "--seconds", strconv.Itoa(svcInfo.StickyMaxAgeSeconds), "--reap",
  1138. "-j", string(endpointChain))
  1139. }
  1140. }
  1141. // Setup probability filter rules only over local endpoints
  1142. for i, endpointChain := range localEndpointChains {
  1143. // Balancing rules in the per-service chain.
  1144. args = append(args[:0],
  1145. "-A", string(svcXlbChain),
  1146. "-m", "comment", "--comment",
  1147. fmt.Sprintf(`"Balancing rule %d for %s"`, i, svcNameString),
  1148. )
  1149. if i < (numLocalEndpoints - 1) {
  1150. // Each rule is a probabilistic match.
  1151. args = append(args,
  1152. "-m", "statistic",
  1153. "--mode", "random",
  1154. "--probability", proxier.probability(numLocalEndpoints-i))
  1155. }
  1156. // The final (or only if n == 1) rule is a guaranteed match.
  1157. args = append(args, "-j", string(endpointChain))
  1158. writeLine(proxier.natRules, args...)
  1159. }
  1160. }
  1161. }
  1162. // Delete chains no longer in use.
  1163. for chain := range existingNATChains {
  1164. if !activeNATChains[chain] {
  1165. chainString := string(chain)
  1166. if !strings.HasPrefix(chainString, "KUBE-SVC-") && !strings.HasPrefix(chainString, "KUBE-SEP-") && !strings.HasPrefix(chainString, "KUBE-FW-") && !strings.HasPrefix(chainString, "KUBE-XLB-") {
  1167. // Ignore chains that aren't ours.
  1168. continue
  1169. }
  1170. // We must (as per iptables) write a chain-line for it, which has
  1171. // the nice effect of flushing the chain. Then we can remove the
  1172. // chain.
  1173. writeBytesLine(proxier.natChains, existingNATChains[chain])
  1174. writeLine(proxier.natRules, "-X", chainString)
  1175. }
  1176. }
  1177. // Finally, tail-call to the nodeports chain. This needs to be after all
  1178. // other service portal rules.
  1179. addresses, err := utilproxy.GetNodeAddresses(proxier.nodePortAddresses, proxier.networkInterfacer)
  1180. if err != nil {
  1181. klog.Errorf("Failed to get node ip address matching nodeport cidr")
  1182. } else {
  1183. isIPv6 := proxier.iptables.IsIpv6()
  1184. for address := range addresses {
  1185. // TODO(thockin, m1093782566): If/when we have dual-stack support we will want to distinguish v4 from v6 zero-CIDRs.
  1186. if utilproxy.IsZeroCIDR(address) {
  1187. args = append(args[:0],
  1188. "-A", string(kubeServicesChain),
  1189. "-m", "comment", "--comment", `"kubernetes service nodeports; NOTE: this must be the last rule in this chain"`,
  1190. "-m", "addrtype", "--dst-type", "LOCAL",
  1191. "-j", string(kubeNodePortsChain))
  1192. writeLine(proxier.natRules, args...)
  1193. // Nothing else matters after the zero CIDR.
  1194. break
  1195. }
  1196. // Ignore IP addresses with incorrect version
  1197. if isIPv6 && !utilnet.IsIPv6String(address) || !isIPv6 && utilnet.IsIPv6String(address) {
  1198. klog.Errorf("IP address %s has incorrect IP version", address)
  1199. continue
  1200. }
  1201. // create nodeport rules for each IP one by one
  1202. args = append(args[:0],
  1203. "-A", string(kubeServicesChain),
  1204. "-m", "comment", "--comment", `"kubernetes service nodeports; NOTE: this must be the last rule in this chain"`,
  1205. "-d", address,
  1206. "-j", string(kubeNodePortsChain))
  1207. writeLine(proxier.natRules, args...)
  1208. }
  1209. }
  1210. // Drop the packets in INVALID state, which would potentially cause
  1211. // unexpected connection reset.
  1212. // https://github.com/kubernetes/kubernetes/issues/74839
  1213. writeLine(proxier.filterRules,
  1214. "-A", string(kubeForwardChain),
  1215. "-m", "conntrack",
  1216. "--ctstate", "INVALID",
  1217. "-j", "DROP",
  1218. )
  1219. // If the masqueradeMark has been added then we want to forward that same
  1220. // traffic, this allows NodePort traffic to be forwarded even if the default
  1221. // FORWARD policy is not accept.
  1222. writeLine(proxier.filterRules,
  1223. "-A", string(kubeForwardChain),
  1224. "-m", "comment", "--comment", `"kubernetes forwarding rules"`,
  1225. "-m", "mark", "--mark", proxier.masqueradeMark,
  1226. "-j", "ACCEPT",
  1227. )
  1228. // The following rules can only be set if clusterCIDR has been defined.
  1229. if len(proxier.clusterCIDR) != 0 {
  1230. // The following two rules ensure the traffic after the initial packet
  1231. // accepted by the "kubernetes forwarding rules" rule above will be
  1232. // accepted, to be as specific as possible the traffic must be sourced
  1233. // or destined to the clusterCIDR (to/from a pod).
  1234. writeLine(proxier.filterRules,
  1235. "-A", string(kubeForwardChain),
  1236. "-s", proxier.clusterCIDR,
  1237. "-m", "comment", "--comment", `"kubernetes forwarding conntrack pod source rule"`,
  1238. "-m", "conntrack",
  1239. "--ctstate", "RELATED,ESTABLISHED",
  1240. "-j", "ACCEPT",
  1241. )
  1242. writeLine(proxier.filterRules,
  1243. "-A", string(kubeForwardChain),
  1244. "-m", "comment", "--comment", `"kubernetes forwarding conntrack pod destination rule"`,
  1245. "-d", proxier.clusterCIDR,
  1246. "-m", "conntrack",
  1247. "--ctstate", "RELATED,ESTABLISHED",
  1248. "-j", "ACCEPT",
  1249. )
  1250. }
  1251. // Write the end-of-table markers.
  1252. writeLine(proxier.filterRules, "COMMIT")
  1253. writeLine(proxier.natRules, "COMMIT")
  1254. // Sync rules.
  1255. // NOTE: NoFlushTables is used so we don't flush non-kubernetes chains in the table
  1256. proxier.iptablesData.Reset()
  1257. proxier.iptablesData.Write(proxier.filterChains.Bytes())
  1258. proxier.iptablesData.Write(proxier.filterRules.Bytes())
  1259. proxier.iptablesData.Write(proxier.natChains.Bytes())
  1260. proxier.iptablesData.Write(proxier.natRules.Bytes())
  1261. klog.V(5).Infof("Restoring iptables rules: %s", proxier.iptablesData.Bytes())
  1262. err = proxier.iptables.RestoreAll(proxier.iptablesData.Bytes(), utiliptables.NoFlushTables, utiliptables.RestoreCounters)
  1263. if err != nil {
  1264. klog.Errorf("Failed to execute iptables-restore: %v", err)
  1265. // Revert new local ports.
  1266. klog.V(2).Infof("Closing local ports after iptables-restore failure")
  1267. utilproxy.RevertPorts(replacementPortsMap, proxier.portsMap)
  1268. return
  1269. }
  1270. for _, lastChangeTriggerTime := range endpointUpdateResult.LastChangeTriggerTimes {
  1271. latency := metrics.SinceInSeconds(lastChangeTriggerTime)
  1272. metrics.NetworkProgrammingLatency.Observe(latency)
  1273. klog.V(4).Infof("Network programming took %f seconds", latency)
  1274. }
  1275. // Close old local ports and save new ones.
  1276. for k, v := range proxier.portsMap {
  1277. if replacementPortsMap[k] == nil {
  1278. v.Close()
  1279. }
  1280. }
  1281. proxier.portsMap = replacementPortsMap
  1282. // Update healthz timestamp.
  1283. if proxier.healthzServer != nil {
  1284. proxier.healthzServer.UpdateTimestamp()
  1285. }
  1286. metrics.SyncProxyRulesLastTimestamp.SetToCurrentTime()
  1287. // Update healthchecks. The endpoints list might include services that are
  1288. // not "OnlyLocal", but the services list will not, and the healthChecker
  1289. // will just drop those endpoints.
  1290. if err := proxier.healthChecker.SyncServices(serviceUpdateResult.HCServiceNodePorts); err != nil {
  1291. klog.Errorf("Error syncing healthcheck services: %v", err)
  1292. }
  1293. if err := proxier.healthChecker.SyncEndpoints(endpointUpdateResult.HCEndpointsLocalIPSize); err != nil {
  1294. klog.Errorf("Error syncing healthcheck endpoints: %v", err)
  1295. }
  1296. // Finish housekeeping.
  1297. // TODO: these could be made more consistent.
  1298. for _, svcIP := range staleServices.UnsortedList() {
  1299. if err := conntrack.ClearEntriesForIP(proxier.exec, svcIP, v1.ProtocolUDP); err != nil {
  1300. klog.Errorf("Failed to delete stale service IP %s connections, error: %v", svcIP, err)
  1301. }
  1302. }
  1303. proxier.deleteEndpointConnections(endpointUpdateResult.StaleEndpoints)
  1304. }
  1305. // Join all words with spaces, terminate with newline and write to buf.
  1306. func writeLine(buf *bytes.Buffer, words ...string) {
  1307. // We avoid strings.Join for performance reasons.
  1308. for i := range words {
  1309. buf.WriteString(words[i])
  1310. if i < len(words)-1 {
  1311. buf.WriteByte(' ')
  1312. } else {
  1313. buf.WriteByte('\n')
  1314. }
  1315. }
  1316. }
  1317. func writeBytesLine(buf *bytes.Buffer, bytes []byte) {
  1318. buf.Write(bytes)
  1319. buf.WriteByte('\n')
  1320. }
  1321. func openLocalPort(lp *utilproxy.LocalPort) (utilproxy.Closeable, error) {
  1322. // For ports on node IPs, open the actual port and hold it, even though we
  1323. // use iptables to redirect traffic.
  1324. // This ensures a) that it's safe to use that port and b) that (a) stays
  1325. // true. The risk is that some process on the node (e.g. sshd or kubelet)
  1326. // is using a port and we give that same port out to a Service. That would
  1327. // be bad because iptables would silently claim the traffic but the process
  1328. // would never know.
  1329. // NOTE: We should not need to have a real listen()ing socket - bind()
  1330. // should be enough, but I can't figure out a way to e2e test without
  1331. // it. Tools like 'ss' and 'netstat' do not show sockets that are
  1332. // bind()ed but not listen()ed, and at least the default debian netcat
  1333. // has no way to avoid about 10 seconds of retries.
  1334. var socket utilproxy.Closeable
  1335. switch lp.Protocol {
  1336. case "tcp":
  1337. listener, err := net.Listen("tcp", net.JoinHostPort(lp.IP, strconv.Itoa(lp.Port)))
  1338. if err != nil {
  1339. return nil, err
  1340. }
  1341. socket = listener
  1342. case "udp":
  1343. addr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(lp.IP, strconv.Itoa(lp.Port)))
  1344. if err != nil {
  1345. return nil, err
  1346. }
  1347. conn, err := net.ListenUDP("udp", addr)
  1348. if err != nil {
  1349. return nil, err
  1350. }
  1351. socket = conn
  1352. default:
  1353. return nil, fmt.Errorf("unknown protocol %q", lp.Protocol)
  1354. }
  1355. klog.V(2).Infof("Opened local port %s", lp.String())
  1356. return socket, nil
  1357. }