github.com/fafucoder/cilium@v1.6.11/cilium/cmd/policy.go (about) 1 // Copyright 2017 Authors of Cilium 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 15 package cmd 16 17 import ( 18 "bufio" 19 "encoding/json" 20 "fmt" 21 "io/ioutil" 22 "os" 23 "path" 24 "path/filepath" 25 "regexp" 26 "strings" 27 28 "github.com/cilium/cilium/pkg/logging/logfields" 29 "github.com/cilium/cilium/pkg/policy/api" 30 31 "github.com/sirupsen/logrus" 32 "github.com/spf13/cobra" 33 ) 34 35 // policyCmd represents the policy command 36 var policyCmd = &cobra.Command{ 37 Use: "policy", 38 Short: "Manage security policies", 39 } 40 41 var ( 42 ignoredMasksSource = []string{".git"} 43 ignoredMasks []*regexp.Regexp 44 ) 45 46 func init() { 47 ignoredMasks = make([]*regexp.Regexp, len(ignoredMasksSource)) 48 49 for i := range ignoredMasksSource { 50 ignoredMasks[i] = regexp.MustCompile(ignoredMasksSource[i]) 51 } 52 53 rootCmd.AddCommand(policyCmd) 54 } 55 56 func getContext(content []byte, offset int64) (int, string, int) { 57 if offset >= int64(len(content)) || offset < 0 { 58 return 0, fmt.Sprintf("[error: Offset %d is out of bounds 0..%d]", offset, len(content)), 0 59 } 60 61 lineN := strings.Count(string(content[:offset]), "\n") + 1 62 63 start := strings.LastIndexByte(string(content[:offset]), '\n') 64 if start == -1 { 65 start = 0 66 } else { 67 start++ 68 } 69 70 end := strings.IndexByte(string(content[start:]), '\n') 71 var l string 72 if end == -1 { 73 l = string(content[start:]) 74 } else { 75 end = end + start 76 l = string(content[start:end]) 77 } 78 79 return lineN, l, (int(offset) - start) 80 } 81 82 func handleUnmarshalError(f string, content []byte, err error) error { 83 switch e := err.(type) { 84 case *json.SyntaxError: 85 line, ctx, off := getContext(content, e.Offset) 86 87 if off <= 1 { 88 return fmt.Errorf("malformed policy, not JSON?") 89 } 90 91 preoff := off - 1 92 pre := make([]byte, preoff) 93 copy(pre, ctx[:preoff]) 94 for i := 0; i < preoff && i < len(pre); i++ { 95 if pre[i] != '\t' { 96 pre[i] = ' ' 97 } 98 } 99 100 return fmt.Errorf("%s:%d: syntax error at offset %d:\n%s\n%s^", 101 path.Base(f), line, off, ctx, pre) 102 case *json.UnmarshalTypeError: 103 line, ctx, off := getContext(content, e.Offset) 104 return fmt.Errorf("%s:%d: unable to assign value '%s' to type '%v':\n%s\n%*c", 105 path.Base(f), line, e.Value, e.Type, ctx, off, '^') 106 default: 107 return fmt.Errorf("%s: unknown error:%s", path.Base(f), err) 108 } 109 } 110 111 func ignoredFile(name string) bool { 112 for i := range ignoredMasks { 113 if ignoredMasks[i].MatchString(name) { 114 logrus.WithField(logfields.Path, name).Debug("Ignoring file") 115 return true 116 } 117 } 118 119 return false 120 } 121 122 func loadPolicyFile(path string) (api.Rules, error) { 123 var content []byte 124 var err error 125 logrus.WithField(logfields.Path, path).Debug("Loading file") 126 127 if path == "-" { 128 content, err = ioutil.ReadAll(bufio.NewReader(os.Stdin)) 129 } else { 130 content, err = ioutil.ReadFile(path) 131 } 132 133 if err != nil { 134 return nil, err 135 } 136 137 var ruleList api.Rules 138 err = json.Unmarshal(content, &ruleList) 139 if err != nil { 140 return nil, handleUnmarshalError(path, content, err) 141 } 142 143 return ruleList, nil 144 } 145 146 func loadPolicy(name string) (api.Rules, error) { 147 logrus.WithField(logfields.Path, name).Debug("Entering directory") 148 149 if name == "-" { 150 return loadPolicyFile(name) 151 } 152 153 if fi, err := os.Stat(name); err != nil { 154 return nil, err 155 } else if fi.Mode().IsRegular() { 156 return loadPolicyFile(name) 157 } else if !fi.Mode().IsDir() { 158 return nil, fmt.Errorf("Error: %s is not a file or a directory", name) 159 } 160 161 files, err := ioutil.ReadDir(name) 162 if err != nil { 163 return nil, err 164 } 165 166 result := api.Rules{} 167 ruleList, err := processAllFilesFirst(name, files) 168 if err != nil { 169 return nil, err 170 } 171 result = append(result, ruleList...) 172 173 ruleList, err = recursiveSearch(name, files) 174 if err != nil { 175 return nil, err 176 } 177 result = append(result, ruleList...) 178 179 logrus.WithField(logfields.Path, name).Debug("Leaving directory") 180 181 return result, nil 182 } 183 184 func processAllFilesFirst(name string, files []os.FileInfo) (api.Rules, error) { 185 result := api.Rules{} 186 187 for _, f := range files { 188 if f.IsDir() || ignoredFile(path.Base(f.Name())) { 189 continue 190 } 191 192 ruleList, err := loadPolicyFile(filepath.Join(name, f.Name())) 193 if err != nil { 194 return nil, err 195 } 196 197 result = append(result, ruleList...) 198 } 199 200 return result, nil 201 } 202 203 func recursiveSearch(name string, files []os.FileInfo) (api.Rules, error) { 204 result := api.Rules{} 205 for _, f := range files { 206 if f.IsDir() { 207 if ignoredFile(path.Base(f.Name())) { 208 continue 209 } 210 subpath := filepath.Join(name, f.Name()) 211 ruleList, err := loadPolicy(subpath) 212 if err != nil { 213 return nil, err 214 } 215 result = append(result, ruleList...) 216 } 217 } 218 return result, nil 219 }