iptables.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. // Copyright 2019 the Kilo 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. package iptables
  15. import (
  16. "fmt"
  17. "net"
  18. "strings"
  19. "sync"
  20. "time"
  21. "github.com/coreos/go-iptables/iptables"
  22. )
  23. // Client represents any type that can administer iptables rules.
  24. type Client interface {
  25. AppendUnique(table string, chain string, rule ...string) error
  26. Delete(table string, chain string, rule ...string) error
  27. Exists(table string, chain string, rule ...string) (bool, error)
  28. ClearChain(table string, chain string) error
  29. DeleteChain(table string, chain string) error
  30. NewChain(table string, chain string) error
  31. }
  32. // Rule is an interface for interacting with iptables objects.
  33. type Rule interface {
  34. Add(Client) error
  35. Delete(Client) error
  36. Exists(Client) (bool, error)
  37. String() string
  38. }
  39. // rule represents an iptables rule.
  40. type rule struct {
  41. table string
  42. chain string
  43. spec []string
  44. }
  45. func (r *rule) Add(client Client) error {
  46. if err := client.AppendUnique(r.table, r.chain, r.spec...); err != nil {
  47. return fmt.Errorf("failed to add iptables rule: %v", err)
  48. }
  49. return nil
  50. }
  51. func (r *rule) Delete(client Client) error {
  52. // Ignore the returned error as an error likely means
  53. // that the rule doesn't exist, which is fine.
  54. client.Delete(r.table, r.chain, r.spec...)
  55. return nil
  56. }
  57. func (r *rule) Exists(client Client) (bool, error) {
  58. return client.Exists(r.table, r.chain, r.spec...)
  59. }
  60. func (r *rule) String() string {
  61. if r == nil {
  62. return ""
  63. }
  64. return fmt.Sprintf("%s_%s_%s", r.table, r.chain, strings.Join(r.spec, "_"))
  65. }
  66. // chain represents an iptables chain.
  67. type chain struct {
  68. table string
  69. chain string
  70. }
  71. func (c *chain) Add(client Client) error {
  72. if err := client.ClearChain(c.table, c.chain); err != nil {
  73. return fmt.Errorf("failed to add iptables chain: %v", err)
  74. }
  75. return nil
  76. }
  77. func (c *chain) Delete(client Client) error {
  78. // The chain must be empty before it can be deleted.
  79. if err := client.ClearChain(c.table, c.chain); err != nil {
  80. return fmt.Errorf("failed to clear iptables chain: %v", err)
  81. }
  82. // Ignore the returned error as an error likely means
  83. // that the chain doesn't exist, which is fine.
  84. client.DeleteChain(c.table, c.chain)
  85. return nil
  86. }
  87. func (c *chain) Exists(client Client) (bool, error) {
  88. // The code for "chain already exists".
  89. existsErr := 1
  90. err := client.NewChain(c.table, c.chain)
  91. se, ok := err.(statusExiter)
  92. switch {
  93. case err == nil:
  94. // If there was no error adding a new chain, then it did not exist.
  95. // Delete it and return false.
  96. client.DeleteChain(c.table, c.chain)
  97. return false, nil
  98. case ok && se.ExitStatus() == existsErr:
  99. return true, nil
  100. default:
  101. return false, err
  102. }
  103. }
  104. func (c *chain) String() string {
  105. if c == nil {
  106. return ""
  107. }
  108. return fmt.Sprintf("%s_%s", c.table, c.chain)
  109. }
  110. // Controller is able to reconcile a given set of iptables rules.
  111. type Controller struct {
  112. client Client
  113. errors chan error
  114. sync.Mutex
  115. rules []Rule
  116. subscribed bool
  117. }
  118. // New generates a new iptables rules controller.
  119. // It expects an IP address length to determine
  120. // whether to operate in IPv4 or IPv6 mode.
  121. func New(ipLength int) (*Controller, error) {
  122. p := iptables.ProtocolIPv4
  123. if ipLength == net.IPv6len {
  124. p = iptables.ProtocolIPv6
  125. }
  126. client, err := iptables.NewWithProtocol(p)
  127. if err != nil {
  128. return nil, fmt.Errorf("failed to create iptables client: %v", err)
  129. }
  130. return &Controller{
  131. client: client,
  132. errors: make(chan error),
  133. }, nil
  134. }
  135. // Run watches for changes to iptables rules and reconciles
  136. // the rules against the desired state.
  137. func (c *Controller) Run(stop <-chan struct{}) (<-chan error, error) {
  138. c.Lock()
  139. if c.subscribed {
  140. c.Unlock()
  141. return c.errors, nil
  142. }
  143. // Ensure a given instance only subscribes once.
  144. c.subscribed = true
  145. c.Unlock()
  146. go func() {
  147. defer close(c.errors)
  148. for {
  149. select {
  150. case <-time.After(5 * time.Second):
  151. case <-stop:
  152. return
  153. }
  154. if err := c.reconcile(); err != nil {
  155. nonBlockingSend(c.errors, fmt.Errorf("failed to reconcile rules: %v", err))
  156. }
  157. }
  158. }()
  159. return c.errors, nil
  160. }
  161. // reconcile makes sure that every rule is still in the backend.
  162. // It does not ensure that the order in the backend is correct.
  163. // If any rule is missing, that rule and all following rules are
  164. // re-added.
  165. func (c *Controller) reconcile() error {
  166. c.Lock()
  167. defer c.Unlock()
  168. for i, r := range c.rules {
  169. ok, err := r.Exists(c.client)
  170. if err != nil {
  171. return fmt.Errorf("failed to check if rule exists: %v", err)
  172. }
  173. if !ok {
  174. if err := c.resetFromIndex(i, c.rules); err != nil {
  175. return fmt.Errorf("failed to add rule: %v", err)
  176. }
  177. break
  178. }
  179. }
  180. return nil
  181. }
  182. // resetFromIndex re-adds all rules starting from the given index.
  183. func (c *Controller) resetFromIndex(i int, rules []Rule) error {
  184. if i >= len(rules) {
  185. return nil
  186. }
  187. for j := i; j < len(rules); j++ {
  188. if err := rules[j].Delete(c.client); err != nil {
  189. return fmt.Errorf("failed to delete rule: %v", err)
  190. }
  191. if err := rules[j].Add(c.client); err != nil {
  192. return fmt.Errorf("failed to add rule: %v", err)
  193. }
  194. }
  195. return nil
  196. }
  197. // deleteFromIndex deletes all rules starting from the given index.
  198. func (c *Controller) deleteFromIndex(i int, rules *[]Rule) error {
  199. if i >= len(*rules) {
  200. return nil
  201. }
  202. for j := i; j < len(*rules); j++ {
  203. if err := (*rules)[j].Delete(c.client); err != nil {
  204. return fmt.Errorf("failed to delete rule: %v", err)
  205. }
  206. (*rules)[j] = nil
  207. }
  208. *rules = (*rules)[:i]
  209. return nil
  210. }
  211. // Set idempotently overwrites any iptables rules previously defined
  212. // for the controller with the given set of rules.
  213. func (c *Controller) Set(rules []Rule) error {
  214. c.Lock()
  215. defer c.Unlock()
  216. var i int
  217. for ; i < len(rules); i++ {
  218. if i < len(c.rules) {
  219. if rules[i].String() != c.rules[i].String() {
  220. if err := c.deleteFromIndex(i, &c.rules); err != nil {
  221. return err
  222. }
  223. }
  224. }
  225. if i >= len(c.rules) {
  226. if err := rules[i].Add(c.client); err != nil {
  227. return fmt.Errorf("failed to add rule: %v", err)
  228. }
  229. c.rules = append(c.rules, rules[i])
  230. }
  231. }
  232. return c.deleteFromIndex(i, &c.rules)
  233. }
  234. // CleanUp will clean up any rules created by the controller.
  235. func (c *Controller) CleanUp() error {
  236. c.Lock()
  237. defer c.Unlock()
  238. return c.deleteFromIndex(0, &c.rules)
  239. }
  240. // IPIPRules returns a set of iptables rules that are necessary
  241. // when traffic between nodes must be encapsulated with IPIP.
  242. func IPIPRules(nodes []*net.IPNet) []Rule {
  243. var rules []Rule
  244. rules = append(rules, &chain{"filter", "KILO-IPIP"})
  245. rules = append(rules, &rule{"filter", "INPUT", []string{"-m", "comment", "--comment", "Kilo: jump to IPIP chain", "-p", "4", "-j", "KILO-IPIP"}})
  246. for _, n := range nodes {
  247. // Accept encapsulated traffic from peers.
  248. rules = append(rules, &rule{"filter", "KILO-IPIP", []string{"-m", "comment", "--comment", "Kilo: allow IPIP traffic", "-s", n.IP.String(), "-j", "ACCEPT"}})
  249. }
  250. // Drop all other IPIP traffic.
  251. rules = append(rules, &rule{"filter", "INPUT", []string{"-m", "comment", "--comment", "Kilo: reject other IPIP traffic", "-p", "4", "-j", "DROP"}})
  252. return rules
  253. }
  254. // ForwardRules returns a set of iptables rules that are necessary
  255. // when traffic must be forwarded for the overlay.
  256. func ForwardRules(subnets ...*net.IPNet) []Rule {
  257. var rules []Rule
  258. for _, subnet := range subnets {
  259. s := subnet.String()
  260. rules = append(rules, []Rule{
  261. // Forward traffic to and from the overlay.
  262. &rule{"filter", "FORWARD", []string{"-s", s, "-j", "ACCEPT"}},
  263. &rule{"filter", "FORWARD", []string{"-d", s, "-j", "ACCEPT"}},
  264. }...)
  265. }
  266. return rules
  267. }
  268. func nonBlockingSend(errors chan<- error, err error) {
  269. select {
  270. case errors <- err:
  271. default:
  272. }
  273. }