github.com/greenpau/go-authcrunch@v1.1.4/pkg/util/addr/utils.go (about) 1 // Copyright 2022 Paul Greenberg greenpau@outlook.com 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 addr 16 17 import ( 18 "fmt" 19 "github.com/greenpau/go-authcrunch/pkg/waf" 20 "net/http" 21 "strings" 22 ) 23 24 const malformedURLStr = "malformed-url" 25 26 // GetSourceHost returns the host or host:port of the request. 27 func GetSourceHost(r *http.Request) string { 28 h := r.Header.Get("X-Forwarded-Host") 29 if !waf.IsMalformedForwardedHost(h, 2, 255) { 30 if h != "" { 31 return h 32 } 33 } 34 return r.Host 35 } 36 37 func parseSourceAddress(addr string) string { 38 if strings.Contains(addr, ",") { 39 addr = strings.TrimSpace(addr) 40 addr = strings.SplitN(addr, ",", 2)[0] 41 } 42 43 switch { 44 case strings.Contains(addr, "["): 45 // Handle IPv6 "[host]:port" address. 46 return parseAddr6(addr) 47 case strings.Contains(addr, "::"): 48 // Handle IPv6 address. 49 return addr 50 } 51 52 if strings.Contains(addr, ":") { 53 parts := strings.Split(addr, ":") 54 if len(parts) > 2 { 55 // Handle IPv6 address. 56 return parts[0] 57 } 58 return parts[0] 59 } 60 61 return addr 62 } 63 64 // GetSourceAddress returns the IP address of the request. 65 func GetSourceAddress(r *http.Request) string { 66 if r.Header.Get("X-Real-Ip") != "" { 67 if !waf.IsMalformedRealIP(r.Header.Get("X-Real-Ip"), 7, 255) { 68 return parseSourceAddress(r.Header.Get("X-Real-Ip")) 69 } 70 } 71 if r.Header.Get("X-Forwarded-For") != "" { 72 if !waf.IsMalformedForwardedFor(r.Header.Get("X-Forwarded-For"), 7, 255) { 73 return parseSourceAddress(r.Header.Get("X-Forwarded-For")) 74 } 75 } 76 return parseSourceAddress(r.RemoteAddr) 77 } 78 79 // GetSourceConnAddress returns the IP address of the HTTP connection. 80 func GetSourceConnAddress(r *http.Request) string { 81 addr := r.RemoteAddr 82 if strings.Contains(addr, ",") { 83 addr = strings.TrimSpace(addr) 84 addr = strings.SplitN(addr, ",", 2)[0] 85 } 86 switch { 87 case strings.Contains(addr, "["): 88 // Handle IPv6 "[host]:port" address. 89 return parseAddr6(addr) 90 case strings.Contains(addr, "::"): 91 // Handle IPv6 address. 92 return addr 93 } 94 if strings.Contains(addr, ":") { 95 parts := strings.Split(addr, ":") 96 if len(parts) > 2 { 97 // Handle IPv6 address. 98 return parts[0] 99 } 100 return parts[0] 101 } 102 return addr 103 } 104 105 func parseAddr6(s string) string { 106 i := strings.IndexByte(s, '[') 107 if i < 0 { 108 return s 109 } 110 j := strings.IndexByte(s, ']') 111 if j < 0 { 112 return s 113 } 114 if i >= j { 115 return s 116 } 117 return s[(i + 1):j] 118 } 119 120 // GetTargetURL returns the URL the user landed on. 121 func GetTargetURL(r *http.Request) string { 122 s, _ := GetCurrentURLWithSuffix(r, "") 123 return s 124 } 125 126 // GetCurrentURLWithSuffix returns current URL based on the provided suffux. 127 func GetCurrentURLWithSuffix(r *http.Request, suffix string) (string, error) { 128 h := r.Header.Get("X-Forwarded-Host") 129 130 if waf.IsMalformedForwardedHost(h, 2, 255) { 131 return malformedURLStr, fmt.Errorf("malformed X-Forwarded-Host header") 132 } 133 134 if h == "" { 135 h = r.Host 136 } 137 138 p := r.Header.Get("X-Forwarded-Proto") 139 if waf.IsMalformedForwardedProto(p, 2, 10) { 140 return malformedURLStr, fmt.Errorf("malformed X-Forwarded-Proto header") 141 } 142 143 if p == "" { 144 if r.TLS == nil { 145 p = "http" 146 } else { 147 p = "https" 148 } 149 } 150 151 port := r.Header.Get("X-Forwarded-Port") 152 if waf.IsMalformedForwardedPort(port, 2, 5) { 153 return malformedURLStr, fmt.Errorf("malformed X-Forwarded-Port header") 154 } 155 156 u := p + "://" + h 157 158 if port != "" { 159 switch port { 160 case "443": 161 if p != "https" { 162 u += ":" + port 163 } 164 case "80": 165 if p != "http" { 166 u += ":" + port 167 } 168 default: 169 u += ":" + port 170 } 171 } 172 173 prefix := r.Header.Get("X-Forwarded-Prefix") 174 u += prefix 175 176 if suffix != "" { 177 i := strings.Index(r.RequestURI, suffix) 178 if i < 0 { 179 return u + r.RequestURI, nil 180 } 181 return u + r.RequestURI[:i] + suffix, nil 182 } 183 184 return u + r.RequestURI, nil 185 }