iptables.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // Copyright 2015 flannel 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. // +build !windows
  15. package network
  16. import (
  17. "fmt"
  18. "strings"
  19. "time"
  20. "github.com/coreos/go-iptables/iptables"
  21. "github.com/flannel-io/flannel/pkg/ip"
  22. "github.com/flannel-io/flannel/subnet"
  23. log "k8s.io/klog"
  24. )
  25. type IPTables interface {
  26. AppendUnique(table string, chain string, rulespec ...string) error
  27. Delete(table string, chain string, rulespec ...string) error
  28. Exists(table string, chain string, rulespec ...string) (bool, error)
  29. }
  30. type IPTablesError interface {
  31. IsNotExist() bool
  32. Error() string
  33. }
  34. type IPTablesRule struct {
  35. table string
  36. chain string
  37. rulespec []string
  38. }
  39. func MasqRules(ipn ip.IP4Net, lease *subnet.Lease) []IPTablesRule {
  40. n := ipn.String()
  41. sn := lease.Subnet.String()
  42. supports_random_fully := false
  43. ipt, err := iptables.New()
  44. if err == nil {
  45. supports_random_fully = ipt.HasRandomFully()
  46. }
  47. if supports_random_fully {
  48. return []IPTablesRule{
  49. // This rule makes sure we don't NAT traffic within overlay network (e.g. coming out of docker0)
  50. {"nat", "POSTROUTING", []string{"-s", n, "-d", n, "-j", "RETURN"}},
  51. // NAT if it's not multicast traffic
  52. {"nat", "POSTROUTING", []string{"-s", n, "!", "-d", "224.0.0.0/4", "-j", "MASQUERADE", "--random-fully"}},
  53. // Prevent performing Masquerade on external traffic which arrives from a Node that owns the container/pod IP address
  54. {"nat", "POSTROUTING", []string{"!", "-s", n, "-d", sn, "-j", "RETURN"}},
  55. // Masquerade anything headed towards flannel from the host
  56. {"nat", "POSTROUTING", []string{"!", "-s", n, "-d", n, "-j", "MASQUERADE", "--random-fully"}},
  57. }
  58. } else {
  59. return []IPTablesRule{
  60. // This rule makes sure we don't NAT traffic within overlay network (e.g. coming out of docker0)
  61. {"nat", "POSTROUTING", []string{"-s", n, "-d", n, "-j", "RETURN"}},
  62. // NAT if it's not multicast traffic
  63. {"nat", "POSTROUTING", []string{"-s", n, "!", "-d", "224.0.0.0/4", "-j", "MASQUERADE"}},
  64. // Prevent performing Masquerade on external traffic which arrives from a Node that owns the container/pod IP address
  65. {"nat", "POSTROUTING", []string{"!", "-s", n, "-d", sn, "-j", "RETURN"}},
  66. // Masquerade anything headed towards flannel from the host
  67. {"nat", "POSTROUTING", []string{"!", "-s", n, "-d", n, "-j", "MASQUERADE"}},
  68. }
  69. }
  70. }
  71. func MasqIP6Rules(ipn ip.IP6Net, lease *subnet.Lease) []IPTablesRule {
  72. n := ipn.String()
  73. sn := lease.IPv6Subnet.String()
  74. supports_random_fully := false
  75. ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv6)
  76. if err == nil {
  77. supports_random_fully = ipt.HasRandomFully()
  78. }
  79. if supports_random_fully {
  80. return []IPTablesRule{
  81. // This rule makes sure we don't NAT traffic within overlay network (e.g. coming out of docker0)
  82. {"nat", "POSTROUTING", []string{"-s", n, "-d", n, "-j", "RETURN"}},
  83. // NAT if it's not multicast traffic
  84. {"nat", "POSTROUTING", []string{"-s", n, "!", "-d", "ff00::/8", "-j", "MASQUERADE", "--random-fully"}},
  85. // Prevent performing Masquerade on external traffic which arrives from a Node that owns the container/pod IP address
  86. {"nat", "POSTROUTING", []string{"!", "-s", n, "-d", sn, "-j", "RETURN"}},
  87. // Masquerade anything headed towards flannel from the host
  88. {"nat", "POSTROUTING", []string{"!", "-s", n, "-d", n, "-j", "MASQUERADE", "--random-fully"}},
  89. }
  90. } else {
  91. return []IPTablesRule{
  92. // This rule makes sure we don't NAT traffic within overlay network (e.g. coming out of docker0)
  93. {"nat", "POSTROUTING", []string{"-s", n, "-d", n, "-j", "RETURN"}},
  94. // NAT if it's not multicast traffic
  95. {"nat", "POSTROUTING", []string{"-s", n, "!", "-d", "ff00::/8", "-j", "MASQUERADE"}},
  96. // Prevent performing Masquerade on external traffic which arrives from a Node that owns the container/pod IP address
  97. {"nat", "POSTROUTING", []string{"!", "-s", n, "-d", sn, "-j", "RETURN"}},
  98. // Masquerade anything headed towards flannel from the host
  99. {"nat", "POSTROUTING", []string{"!", "-s", n, "-d", n, "-j", "MASQUERADE"}},
  100. }
  101. }
  102. }
  103. func ForwardRules(flannelNetwork string) []IPTablesRule {
  104. return []IPTablesRule{
  105. // These rules allow traffic to be forwarded if it is to or from the flannel network range.
  106. {"filter", "FORWARD", []string{"-s", flannelNetwork, "-j", "ACCEPT"}},
  107. {"filter", "FORWARD", []string{"-d", flannelNetwork, "-j", "ACCEPT"}},
  108. }
  109. }
  110. func ipTablesRulesExist(ipt IPTables, rules []IPTablesRule) (bool, error) {
  111. for _, rule := range rules {
  112. exists, err := ipt.Exists(rule.table, rule.chain, rule.rulespec...)
  113. if err != nil {
  114. // this shouldn't ever happen
  115. return false, fmt.Errorf("failed to check rule existence: %v", err)
  116. }
  117. if !exists {
  118. return false, nil
  119. }
  120. }
  121. return true, nil
  122. }
  123. func SetupAndEnsureIPTables(rules []IPTablesRule, resyncPeriod int) {
  124. ipt, err := iptables.New()
  125. if err != nil {
  126. // if we can't find iptables, give up and return
  127. log.Errorf("Failed to setup IPTables. iptables binary was not found: %v", err)
  128. return
  129. }
  130. defer func() {
  131. teardownIPTables(ipt, rules)
  132. }()
  133. for {
  134. // Ensure that all the iptables rules exist every 5 seconds
  135. if err := ensureIPTables(ipt, rules); err != nil {
  136. log.Errorf("Failed to ensure iptables rules: %v", err)
  137. }
  138. time.Sleep(time.Duration(resyncPeriod) * time.Second)
  139. }
  140. }
  141. func SetupAndEnsureIP6Tables(rules []IPTablesRule, resyncPeriod int) {
  142. ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv6)
  143. if err != nil {
  144. // if we can't find iptables, give up and return
  145. log.Errorf("Failed to setup IP6Tables. iptables binary was not found: %v", err)
  146. return
  147. }
  148. defer func() {
  149. teardownIPTables(ipt, rules)
  150. }()
  151. for {
  152. // Ensure that all the iptables rules exist every 5 seconds
  153. if err := ensureIPTables(ipt, rules); err != nil {
  154. log.Errorf("Failed to ensure iptables rules: %v", err)
  155. }
  156. time.Sleep(time.Duration(resyncPeriod) * time.Second)
  157. }
  158. }
  159. // DeleteIPTables delete specified iptables rules
  160. func DeleteIPTables(rules []IPTablesRule) error {
  161. ipt, err := iptables.New()
  162. if err != nil {
  163. // if we can't find iptables, give up and return
  164. log.Errorf("Failed to setup IPTables. iptables binary was not found: %v", err)
  165. return err
  166. }
  167. teardownIPTables(ipt, rules)
  168. return nil
  169. }
  170. // DeleteIP6Tables delete specified iptables rules
  171. func DeleteIP6Tables(rules []IPTablesRule) error {
  172. ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv6)
  173. if err != nil {
  174. // if we can't find iptables, give up and return
  175. log.Errorf("Failed to setup IP6Tables. iptables binary was not found: %v", err)
  176. return err
  177. }
  178. teardownIPTables(ipt, rules)
  179. return nil
  180. }
  181. func ensureIPTables(ipt IPTables, rules []IPTablesRule) error {
  182. exists, err := ipTablesRulesExist(ipt, rules)
  183. if err != nil {
  184. return fmt.Errorf("Error checking rule existence: %v", err)
  185. }
  186. if exists {
  187. // if all the rules already exist, no need to do anything
  188. return nil
  189. }
  190. // Otherwise, teardown all the rules and set them up again
  191. // We do this because the order of the rules is important
  192. log.Info("Some iptables rules are missing; deleting and recreating rules")
  193. if err = teardownIPTables(ipt, rules); err != nil {
  194. return fmt.Errorf("Error tearing down rules: %v", err)
  195. }
  196. if err = setupIPTables(ipt, rules); err != nil {
  197. return fmt.Errorf("Error setting up rules: %v", err)
  198. }
  199. return nil
  200. }
  201. func setupIPTables(ipt IPTables, rules []IPTablesRule) error {
  202. for _, rule := range rules {
  203. log.Info("Adding iptables rule: ", strings.Join(rule.rulespec, " "))
  204. err := ipt.AppendUnique(rule.table, rule.chain, rule.rulespec...)
  205. if err != nil {
  206. return fmt.Errorf("failed to insert IPTables rule: %v", err)
  207. }
  208. }
  209. return nil
  210. }
  211. func teardownIPTables(ipt IPTables, rules []IPTablesRule) error {
  212. for _, rule := range rules {
  213. log.Info("Deleting iptables rule: ", strings.Join(rule.rulespec, " "))
  214. err := ipt.Delete(rule.table, rule.chain, rule.rulespec...)
  215. if err != nil {
  216. e := err.(IPTablesError)
  217. // If this error is because the rule is already deleted, the message from iptables will be
  218. // "Bad rule (does a matching rule exist in that chain?)". These are safe to ignore.
  219. // However other errors (like EAGAIN caused by other things not respecting the xtables.lock)
  220. // should halt the ensure process. Otherwise rules can get out of order when a rule we think
  221. // is deleted is actually still in the chain.
  222. // This will leave the rules incomplete until the next successful reconciliation loop.
  223. if !e.IsNotExist() {
  224. return err
  225. }
  226. }
  227. }
  228. return nil
  229. }