github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podmanV2/parse/net.go (about) 1 //nolint 2 // most of these validate and parse functions have been taken from projectatomic/docker 3 // and modified for cri-o 4 package parse 5 6 import ( 7 "bufio" 8 "fmt" 9 "net" 10 "net/url" 11 "os" 12 "regexp" 13 "strings" 14 15 "github.com/pkg/errors" 16 ) 17 18 const ( 19 Protocol_TCP Protocol = 0 20 Protocol_UDP Protocol = 1 21 ) 22 23 type Protocol int32 24 25 // PortMapping specifies the port mapping configurations of a sandbox. 26 type PortMapping struct { 27 // Protocol of the port mapping. 28 Protocol Protocol `protobuf:"varint,1,opt,name=protocol,proto3,enum=runtime.Protocol" json:"protocol,omitempty"` 29 // Port number within the container. Default: 0 (not specified). 30 ContainerPort int32 `protobuf:"varint,2,opt,name=container_port,json=containerPort,proto3" json:"container_port,omitempty"` 31 // Port number on the host. Default: 0 (not specified). 32 HostPort int32 `protobuf:"varint,3,opt,name=host_port,json=hostPort,proto3" json:"host_port,omitempty"` 33 // Host IP. 34 HostIp string `protobuf:"bytes,4,opt,name=host_ip,json=hostIp,proto3" json:"host_ip,omitempty"` 35 } 36 37 // Note: for flags that are in the form <number><unit>, use the RAMInBytes function 38 // from the units package in docker/go-units/size.go 39 40 var ( 41 whiteSpaces = " \t" 42 alphaRegexp = regexp.MustCompile(`[a-zA-Z]`) 43 domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`) 44 ) 45 46 // validateExtraHost validates that the specified string is a valid extrahost and returns it. 47 // ExtraHost is in the form of name:ip where the ip has to be a valid ip (ipv4 or ipv6). 48 // for add-host flag 49 func ValidateExtraHost(val string) (string, error) { //nolint 50 // allow for IPv6 addresses in extra hosts by only splitting on first ":" 51 arr := strings.SplitN(val, ":", 2) 52 if len(arr) != 2 || len(arr[0]) == 0 { 53 return "", fmt.Errorf("bad format for add-host: %q", val) 54 } 55 if _, err := validateIPAddress(arr[1]); err != nil { 56 return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1]) 57 } 58 return val, nil 59 } 60 61 // validateIPAddress validates an Ip address. 62 // for dns, ip, and ip6 flags also 63 func validateIPAddress(val string) (string, error) { 64 var ip = net.ParseIP(strings.TrimSpace(val)) 65 if ip != nil { 66 return ip.String(), nil 67 } 68 return "", fmt.Errorf("%s is not an ip address", val) 69 } 70 71 func ValidateDomain(val string) (string, error) { 72 if alphaRegexp.FindString(val) == "" { 73 return "", fmt.Errorf("%s is not a valid domain", val) 74 } 75 ns := domainRegexp.FindSubmatch([]byte(val)) 76 if len(ns) > 0 && len(ns[1]) < 255 { 77 return string(ns[1]), nil 78 } 79 return "", fmt.Errorf("%s is not a valid domain", val) 80 } 81 82 // GetAllLabels retrieves all labels given a potential label file and a number 83 // of labels provided from the command line. 84 func GetAllLabels(labelFile, inputLabels []string) (map[string]string, error) { 85 labels := make(map[string]string) 86 for _, file := range labelFile { 87 // Use of parseEnvFile still seems safe, as it's missing the 88 // extra parsing logic of parseEnv. 89 // There's an argument that we SHOULD be doing that parsing for 90 // all environment variables, even those sourced from files, but 91 // that would require a substantial rework. 92 if err := parseEnvFile(labels, file); err != nil { 93 // FIXME: parseEnvFile is using parseEnv, so we need to add extra 94 // logic for labels. 95 return nil, err 96 } 97 } 98 for _, label := range inputLabels { 99 split := strings.SplitN(label, "=", 2) 100 if split[0] == "" { 101 return nil, errors.Errorf("invalid label format: %q", label) 102 } 103 value := "" 104 if len(split) > 1 { 105 value = split[1] 106 } 107 labels[split[0]] = value 108 } 109 return labels, nil 110 } 111 112 func parseEnv(env map[string]string, line string) error { 113 data := strings.SplitN(line, "=", 2) 114 115 // catch invalid variables such as "=" or "=A" 116 if data[0] == "" { 117 return errors.Errorf("invalid environment variable: %q", line) 118 } 119 120 // trim the front of a variable, but nothing else 121 name := strings.TrimLeft(data[0], whiteSpaces) 122 if strings.ContainsAny(name, whiteSpaces) { 123 return errors.Errorf("name %q has white spaces, poorly formatted name", name) 124 } 125 126 if len(data) > 1 { 127 env[name] = data[1] 128 } else { 129 if strings.HasSuffix(name, "*") { 130 name = strings.TrimSuffix(name, "*") 131 for _, e := range os.Environ() { 132 part := strings.SplitN(e, "=", 2) 133 if len(part) < 2 { 134 continue 135 } 136 if strings.HasPrefix(part[0], name) { 137 env[part[0]] = part[1] 138 } 139 } 140 } else { 141 // if only a pass-through variable is given, clean it up. 142 if val, ok := os.LookupEnv(name); ok { 143 env[name] = val 144 } 145 } 146 } 147 return nil 148 } 149 150 // parseEnvFile reads a file with environment variables enumerated by lines 151 func parseEnvFile(env map[string]string, filename string) error { 152 fh, err := os.Open(filename) 153 if err != nil { 154 return err 155 } 156 defer fh.Close() 157 158 scanner := bufio.NewScanner(fh) 159 for scanner.Scan() { 160 // trim the line from all leading whitespace first 161 line := strings.TrimLeft(scanner.Text(), whiteSpaces) 162 // line is not empty, and not starting with '#' 163 if len(line) > 0 && !strings.HasPrefix(line, "#") { 164 if err := parseEnv(env, line); err != nil { 165 return err 166 } 167 } 168 } 169 return scanner.Err() 170 } 171 172 // ValidateFileName returns an error if filename contains ":" 173 // as it is currently not supported 174 func ValidateFileName(filename string) error { 175 if strings.Contains(filename, ":") { 176 return errors.Errorf("invalid filename (should not contain ':') %q", filename) 177 } 178 return nil 179 } 180 181 // ValidURL checks a string urlStr is a url or not 182 func ValidURL(urlStr string) error { 183 _, err := url.ParseRequestURI(urlStr) 184 if err != nil { 185 return errors.Wrapf(err, "invalid url path: %q", urlStr) 186 } 187 return nil 188 }