go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/auth/addr.go (about) 1 // Copyright 2015 The LUCI 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 15 package auth 16 17 import ( 18 "errors" 19 "fmt" 20 "net" 21 "strings" 22 ) 23 24 // parseRemoteIP parses the IP address from the supplied HTTP request RemoteAddr 25 // string. 26 // 27 // The HTTP library's representation of remote address says that it is a 28 // "host:port" pair. They lie. The following permutations have been observed: 29 // - ipv4:port (Standard) 30 // - ipv4 (GAE) 31 // - ipv6 (GAE) 32 // - [ipv6]:port (GAE Managed VM) 33 // 34 // Note that IPv6 addresses have colons in them. 35 // 36 // If the remote address is blank, "0.0.0.0" will be returned. 37 func parseRemoteIP(a string) (net.IP, error) { 38 if a == "" { 39 return net.IPv4(0, 0, 0, 0), nil 40 } 41 42 // IPv6 in braces with or without port. 43 if strings.HasPrefix(a, "[") { 44 idx := strings.LastIndex(a, "]") 45 if idx < 0 { 46 return nil, errors.New("missing closing brace on IPv6 address") 47 } 48 a = a[1:idx] 49 } 50 51 // Parse as a standalone IPv4/IPv6 address (no port). 52 if ip := net.ParseIP(a); ip != nil { 53 return ip, nil 54 } 55 56 // Is there a port? Strip and try again. 57 if idx := strings.LastIndex(a, ":"); idx >= 0 { 58 if ip := net.ParseIP(a[:idx]); ip != nil { 59 return ip, nil 60 } 61 } 62 63 return nil, fmt.Errorf("don't know how to parse: %q", a) 64 }