ipmasq_linux.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Copyright 2015 CNI 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 ip
  15. import (
  16. "fmt"
  17. "net"
  18. "github.com/coreos/go-iptables/iptables"
  19. )
  20. // SetupIPMasq installs iptables rules to masquerade traffic
  21. // coming from ip of ipn and going outside of ipn
  22. func SetupIPMasq(ipn *net.IPNet, chain string, comment string) error {
  23. isV6 := ipn.IP.To4() == nil
  24. var ipt *iptables.IPTables
  25. var err error
  26. var multicastNet string
  27. if isV6 {
  28. ipt, err = iptables.NewWithProtocol(iptables.ProtocolIPv6)
  29. multicastNet = "ff00::/8"
  30. } else {
  31. ipt, err = iptables.NewWithProtocol(iptables.ProtocolIPv4)
  32. multicastNet = "224.0.0.0/4"
  33. }
  34. if err != nil {
  35. return fmt.Errorf("failed to locate iptables: %v", err)
  36. }
  37. // Create chain if doesn't exist
  38. exists := false
  39. chains, err := ipt.ListChains("nat")
  40. if err != nil {
  41. return fmt.Errorf("failed to list chains: %v", err)
  42. }
  43. for _, ch := range chains {
  44. if ch == chain {
  45. exists = true
  46. break
  47. }
  48. }
  49. if !exists {
  50. if err = ipt.NewChain("nat", chain); err != nil {
  51. return err
  52. }
  53. }
  54. // Packets to this network should not be touched
  55. if err := ipt.AppendUnique("nat", chain, "-d", ipn.String(), "-j", "ACCEPT", "-m", "comment", "--comment", comment); err != nil {
  56. return err
  57. }
  58. // Don't masquerade multicast - pods should be able to talk to other pods
  59. // on the local network via multicast.
  60. if err := ipt.AppendUnique("nat", chain, "!", "-d", multicastNet, "-j", "MASQUERADE", "-m", "comment", "--comment", comment); err != nil {
  61. return err
  62. }
  63. // Packets from the specific IP of this network will hit the chain
  64. return ipt.AppendUnique("nat", "POSTROUTING", "-s", ipn.IP.String(), "-j", chain, "-m", "comment", "--comment", comment)
  65. }
  66. // TeardownIPMasq undoes the effects of SetupIPMasq
  67. func TeardownIPMasq(ipn *net.IPNet, chain string, comment string) error {
  68. isV6 := ipn.IP.To4() == nil
  69. var ipt *iptables.IPTables
  70. var err error
  71. if isV6 {
  72. ipt, err = iptables.NewWithProtocol(iptables.ProtocolIPv6)
  73. } else {
  74. ipt, err = iptables.NewWithProtocol(iptables.ProtocolIPv4)
  75. }
  76. if err != nil {
  77. return fmt.Errorf("failed to locate iptables: %v", err)
  78. }
  79. err = ipt.Delete("nat", "POSTROUTING", "-s", ipn.IP.String(), "-j", chain, "-m", "comment", "--comment", comment)
  80. if err != nil && !isNotExist(err) {
  81. return err
  82. }
  83. // for downward compatibility
  84. err = ipt.Delete("nat", "POSTROUTING", "-s", ipn.String(), "-j", chain, "-m", "comment", "--comment", comment)
  85. if err != nil && !isNotExist(err) {
  86. return err
  87. }
  88. err = ipt.ClearChain("nat", chain)
  89. if err != nil && !isNotExist(err) {
  90. return err
  91. }
  92. err = ipt.DeleteChain("nat", chain)
  93. if err != nil && !isNotExist(err) {
  94. return err
  95. }
  96. return nil
  97. }
  98. // isNotExist returnst true if the error is from iptables indicating
  99. // that the target does not exist.
  100. func isNotExist(err error) bool {
  101. e, ok := err.(*iptables.Error)
  102. if !ok {
  103. return false
  104. }
  105. return e.IsNotExist()
  106. }