secgrouprules_acl.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Copyright 2019 Yunion
  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 ovn
  15. import (
  16. "fmt"
  17. "strconv"
  18. "strings"
  19. "yunion.io/x/log"
  20. "yunion.io/x/ovsdb/schema/ovn_nb"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/util/regutils"
  23. "yunion.io/x/pkg/util/secrules"
  24. agentmodels "yunion.io/x/onecloud/pkg/vpcagent/models"
  25. )
  26. const (
  27. errBadSecgroupRule = errors.Error("bad security group rule")
  28. )
  29. const (
  30. aclDirToLport = "to-lport"
  31. aclDirFromLport = "from-lport"
  32. )
  33. func ruleToAcl(lport string, rule *agentmodels.SecurityGroupRule, enableIPv6 bool) (*ovn_nb.ACL, error) {
  34. var (
  35. dir string
  36. action string
  37. match string
  38. matches []string
  39. l3subfn string
  40. l4subfn string
  41. errs []error
  42. )
  43. switch secrules.TSecurityRuleDirection(rule.Direction) {
  44. case secrules.SecurityRuleIngress:
  45. dir = aclDirToLport
  46. l3subfn = "src"
  47. l4subfn = "dst"
  48. matches = append(matches, fmt.Sprintf("outport == %q", lport))
  49. case secrules.SecurityRuleEgress:
  50. dir = aclDirFromLport
  51. l3subfn = "dst"
  52. l4subfn = "dst"
  53. matches = append(matches, fmt.Sprintf("inport == %q", lport))
  54. default:
  55. return nil, errors.Wrapf(errBadSecgroupRule, "unknown direction %q", rule.Direction)
  56. }
  57. switch secrules.TSecurityRuleAction(rule.Action) {
  58. case secrules.SecurityRuleAllow:
  59. action = "allow-related"
  60. case secrules.SecurityRuleDeny:
  61. action = "drop"
  62. default:
  63. return nil, errors.Wrapf(errBadSecgroupRule, "unknown action %q", rule.Action)
  64. }
  65. addL3Match := func() {
  66. if enableIPv6 {
  67. matches = append(matches, "(ip4 || ip6)")
  68. } else {
  69. matches = append(matches, "ip4")
  70. }
  71. if cidr := strings.TrimSpace(rule.CIDR); cidr != "" {
  72. if regutils.MatchCIDR(cidr) {
  73. matches = append(matches, fmt.Sprintf("ip4.%s == %s", l3subfn, cidr))
  74. } else if regutils.MatchCIDR6(cidr) {
  75. matches = append(matches, fmt.Sprintf("ip6.%s == %s", l3subfn, cidr))
  76. } else {
  77. log.Debugf("invalid cidr %s, ignore", cidr)
  78. }
  79. }
  80. }
  81. addL4Match := func(l4proto string) {
  82. var (
  83. l4portfn = fmt.Sprintf("%s.%s", l4proto, l4subfn)
  84. portMatches []string
  85. )
  86. parsePort := func(pstr string) (int, error) {
  87. pn, err := strconv.ParseUint(pstr, 10, 16)
  88. if err != nil {
  89. return -1, err
  90. }
  91. return int(pn), nil
  92. }
  93. for _, pstr := range strings.Split(rule.Ports, ",") {
  94. pstr = strings.TrimSpace(pstr)
  95. if pstr == "" {
  96. continue
  97. }
  98. if i := strings.Index(pstr, "-"); i >= 0 {
  99. spstr := strings.TrimSpace(pstr[:i])
  100. epstr := strings.TrimSpace(pstr[i+1:])
  101. if spstr == "" || epstr == "" {
  102. continue
  103. }
  104. spn, err := parsePort(spstr)
  105. if err != nil {
  106. errs = append(errs, errors.Wrap(err, "start port"))
  107. }
  108. epn, err := parsePort(epstr)
  109. if err != nil {
  110. errs = append(errs, errors.Wrap(err, "end port"))
  111. }
  112. if spn > epn {
  113. spn, epn = epn, spn
  114. }
  115. if spn < epn {
  116. portMatches = append(portMatches,
  117. fmt.Sprintf("( %s >= %d && %s <= %d )",
  118. l4portfn, spn, l4portfn, epn))
  119. } else /* spn == epn */ {
  120. portMatches = append(portMatches,
  121. fmt.Sprintf("%s == %d", l4portfn, spn))
  122. }
  123. } else {
  124. if pn, err := parsePort(pstr); err != nil {
  125. errs = append(errs, errors.Wrap(err, "port"))
  126. } else {
  127. portMatches = append(portMatches,
  128. fmt.Sprintf("%s == %d", l4portfn, pn))
  129. }
  130. }
  131. }
  132. matches = append(matches, l4proto)
  133. if len(portMatches) > 0 {
  134. portMatch := strings.Join(portMatches, " || ")
  135. if len(portMatches) > 1 {
  136. portMatch = "( " + portMatch + " )"
  137. }
  138. matches = append(matches, portMatch)
  139. }
  140. }
  141. switch rule.Protocol {
  142. case "":
  143. // noop
  144. case "arp":
  145. matches = append(matches, "arp")
  146. case secrules.PROTO_ANY:
  147. addL3Match()
  148. case secrules.PROTO_TCP:
  149. addL3Match()
  150. addL4Match("tcp")
  151. case secrules.PROTO_UDP:
  152. addL3Match()
  153. addL4Match("udp")
  154. case secrules.PROTO_ICMP:
  155. addL3Match()
  156. if enableIPv6 {
  157. matches = append(matches, "(icmp4 || icmp6)")
  158. } else {
  159. matches = append(matches, "icmp4")
  160. }
  161. default:
  162. return nil, errors.Wrapf(errBadSecgroupRule, "unknown protocol %q", rule.Protocol)
  163. }
  164. if len(errs) > 0 {
  165. return nil, errors.NewAggregate(errs)
  166. }
  167. match = strings.Join(matches, " && ")
  168. acl := &ovn_nb.ACL{
  169. Priority: int64(rule.Priority),
  170. Direction: dir,
  171. Match: match,
  172. Action: action,
  173. }
  174. return acl, nil
  175. }