save_restore.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /*
  2. Copyright 2014 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. import (
  15. "bytes"
  16. "fmt"
  17. )
  18. var (
  19. commitBytes = []byte("COMMIT")
  20. spaceBytes = []byte(" ")
  21. )
  22. // MakeChainLine return an iptables-save/restore formatted chain line given a Chain
  23. func MakeChainLine(chain Chain) string {
  24. return fmt.Sprintf(":%s - [0:0]", chain)
  25. }
  26. // GetChainLines parses a table's iptables-save data to find chains in the table.
  27. // It returns a map of iptables.Chain to []byte where the []byte is the chain line
  28. // from save (with counters etc.).
  29. // Note that to avoid allocations memory is SHARED with save.
  30. func GetChainLines(table Table, save []byte) map[Chain][]byte {
  31. chainsMap := make(map[Chain][]byte)
  32. tablePrefix := []byte("*" + string(table))
  33. readIndex := 0
  34. // find beginning of table
  35. for readIndex < len(save) {
  36. line, n := readLine(readIndex, save)
  37. readIndex = n
  38. if bytes.HasPrefix(line, tablePrefix) {
  39. break
  40. }
  41. }
  42. // parse table lines
  43. for readIndex < len(save) {
  44. line, n := readLine(readIndex, save)
  45. readIndex = n
  46. if len(line) == 0 {
  47. continue
  48. }
  49. if bytes.HasPrefix(line, commitBytes) || line[0] == '*' {
  50. break
  51. } else if line[0] == '#' {
  52. continue
  53. } else if line[0] == ':' && len(line) > 1 {
  54. // We assume that the <line> contains space - chain lines have 3 fields,
  55. // space delimited. If there is no space, this line will panic.
  56. spaceIndex := bytes.Index(line, spaceBytes)
  57. if spaceIndex == -1 {
  58. panic(fmt.Sprintf("Unexpected chain line in iptables-save output: %v", string(line)))
  59. }
  60. chain := Chain(line[1:spaceIndex])
  61. chainsMap[chain] = line
  62. }
  63. }
  64. return chainsMap
  65. }
  66. func readLine(readIndex int, byteArray []byte) ([]byte, int) {
  67. currentReadIndex := readIndex
  68. // consume left spaces
  69. for currentReadIndex < len(byteArray) {
  70. if byteArray[currentReadIndex] == ' ' {
  71. currentReadIndex++
  72. } else {
  73. break
  74. }
  75. }
  76. // leftTrimIndex stores the left index of the line after the line is left-trimmed
  77. leftTrimIndex := currentReadIndex
  78. // rightTrimIndex stores the right index of the line after the line is right-trimmed
  79. // it is set to -1 since the correct value has not yet been determined.
  80. rightTrimIndex := -1
  81. for ; currentReadIndex < len(byteArray); currentReadIndex++ {
  82. if byteArray[currentReadIndex] == ' ' {
  83. // set rightTrimIndex
  84. if rightTrimIndex == -1 {
  85. rightTrimIndex = currentReadIndex
  86. }
  87. } else if (byteArray[currentReadIndex] == '\n') || (currentReadIndex == (len(byteArray) - 1)) {
  88. // end of line or byte buffer is reached
  89. if currentReadIndex <= leftTrimIndex {
  90. return nil, currentReadIndex + 1
  91. }
  92. // set the rightTrimIndex
  93. if rightTrimIndex == -1 {
  94. rightTrimIndex = currentReadIndex
  95. if currentReadIndex == (len(byteArray)-1) && (byteArray[currentReadIndex] != '\n') {
  96. // ensure that the last character is part of the returned string,
  97. // unless the last character is '\n'
  98. rightTrimIndex = currentReadIndex + 1
  99. }
  100. }
  101. // Avoid unnecessary allocation.
  102. return byteArray[leftTrimIndex:rightTrimIndex], currentReadIndex + 1
  103. } else {
  104. // unset rightTrimIndex
  105. rightTrimIndex = -1
  106. }
  107. }
  108. return nil, currentReadIndex
  109. }