github.com/aquanetwork/aquachain@v1.7.8/rpc/http.go (about) 1 // Copyright 2015 The aquachain Authors 2 // This file is part of the aquachain library. 3 // 4 // The aquachain library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The aquachain library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the aquachain library. If not, see <http://www.gnu.org/licenses/>. 16 17 package rpc 18 19 import ( 20 "bytes" 21 "context" 22 "encoding/json" 23 "errors" 24 "fmt" 25 "io" 26 "io/ioutil" 27 "mime" 28 "net" 29 "net/http" 30 "sync" 31 "time" 32 33 "strings" 34 35 "github.com/rs/cors" 36 "gitlab.com/aquachain/aquachain/common/log" 37 ) 38 39 const ( 40 contentType = "application/json" 41 maxHTTPRequestContentLength = 1024 * 128 42 ) 43 44 var nullAddr, _ = net.ResolveTCPAddr("tcp", "127.0.0.1:0") 45 46 type httpConn struct { 47 client *http.Client 48 req *http.Request 49 closeOnce sync.Once 50 closed chan struct{} 51 } 52 53 // httpConn is treated specially by Client. 54 func (hc *httpConn) LocalAddr() net.Addr { return nullAddr } 55 func (hc *httpConn) RemoteAddr() net.Addr { return nullAddr } 56 func (hc *httpConn) SetReadDeadline(time.Time) error { return nil } 57 func (hc *httpConn) SetWriteDeadline(time.Time) error { return nil } 58 func (hc *httpConn) SetDeadline(time.Time) error { return nil } 59 func (hc *httpConn) Write([]byte) (int, error) { panic("Write called") } 60 61 func (hc *httpConn) Read(b []byte) (int, error) { 62 <-hc.closed 63 return 0, io.EOF 64 } 65 66 func (hc *httpConn) Close() error { 67 hc.closeOnce.Do(func() { close(hc.closed) }) 68 return nil 69 } 70 71 // DialHTTPWithClient creates a new RPC client that connects to an RPC server over HTTP 72 // using the provided HTTP Client. 73 func DialHTTPWithClient(endpoint string, client *http.Client) (*Client, error) { 74 req, err := http.NewRequest(http.MethodPost, endpoint, nil) 75 if err != nil { 76 return nil, err 77 } 78 req.Header.Set("Content-Type", contentType) 79 req.Header.Set("Accept", contentType) 80 81 initctx := context.Background() 82 return newClient(initctx, func(context.Context) (net.Conn, error) { 83 return &httpConn{client: client, req: req, closed: make(chan struct{})}, nil 84 }) 85 } 86 87 // DialHTTP creates a new RPC client that connects to an RPC server over HTTP. 88 func DialHTTP(endpoint string) (*Client, error) { 89 return DialHTTPWithClient(endpoint, new(http.Client)) 90 } 91 92 func (c *Client) sendHTTP(ctx context.Context, op *requestOp, msg interface{}) error { 93 hc := c.writeConn.(*httpConn) 94 respBody, err := hc.doRequest(ctx, msg) 95 if err != nil { 96 return err 97 } 98 defer respBody.Close() 99 var respmsg jsonrpcMessage 100 if err := json.NewDecoder(respBody).Decode(&respmsg); err != nil { 101 return err 102 } 103 op.resp <- &respmsg 104 return nil 105 } 106 107 func (c *Client) sendBatchHTTP(ctx context.Context, op *requestOp, msgs []*jsonrpcMessage) error { 108 hc := c.writeConn.(*httpConn) 109 respBody, err := hc.doRequest(ctx, msgs) 110 if err != nil { 111 return err 112 } 113 defer respBody.Close() 114 var respmsgs []jsonrpcMessage 115 if err := json.NewDecoder(respBody).Decode(&respmsgs); err != nil { 116 return err 117 } 118 for i := 0; i < len(respmsgs); i++ { 119 op.resp <- &respmsgs[i] 120 } 121 return nil 122 } 123 124 func (hc *httpConn) doRequest(ctx context.Context, msg interface{}) (io.ReadCloser, error) { 125 body, err := json.Marshal(msg) 126 if err != nil { 127 return nil, err 128 } 129 req := hc.req.WithContext(ctx) 130 req.Body = ioutil.NopCloser(bytes.NewReader(body)) 131 req.ContentLength = int64(len(body)) 132 133 resp, err := hc.client.Do(req) 134 if err != nil { 135 return nil, err 136 } 137 return resp.Body, nil 138 } 139 140 // httpReadWriteNopCloser wraps a io.Reader and io.Writer with a NOP Close method. 141 type httpReadWriteNopCloser struct { 142 io.Reader 143 io.Writer 144 } 145 146 // Close does nothing and returns always nil 147 func (t *httpReadWriteNopCloser) Close() error { 148 return nil 149 } 150 151 // NewHTTPServer creates a new HTTP RPC server around an API provider. 152 // 153 // Deprecated: Server implements http.Handler 154 func NewHTTPServer(cors []string, vhosts []string, allowIP []string, srv *Server) *http.Server { 155 // Wrap the CORS-handler within a host-handler 156 handler := newCorsHandler(srv, cors) 157 handler = newVHostHandler(vhosts, handler) 158 handler = newAllowIPHandler(allowIP, handler) 159 return &http.Server{Handler: handler} 160 } 161 162 func getip(r *http.Request) string { 163 if ip := r.Header.Get("X-FORWARDED-FOR"); ip != "" { 164 return ip 165 } 166 return r.RemoteAddr 167 } 168 169 // ServeHTTP serves JSON-RPC requests over HTTP. 170 func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { 171 // Permit dumb empty requests for remote health-checks (AWS) 172 if r.Method == http.MethodGet && r.ContentLength == 0 && r.URL.RawQuery == "" { 173 return 174 } 175 uip := getip(r) 176 log.Debug("handling http request", "from", uip, "path", r.URL.Path, "ua", r.UserAgent(), "http", r.Method, "host", r.Host, "size", r.ContentLength) 177 if code, err := validateRequest(r); err != nil { 178 log.Debug("invalid request", "from", uip, "size", r.ContentLength) 179 http.Error(w, err.Error(), code) 180 return 181 } 182 // All checks passed, create a codec that reads direct from the request body 183 // untilEOF and writes the response to w and order the server to process a 184 // single request. 185 body := io.LimitReader(r.Body, maxHTTPRequestContentLength) 186 codec := NewJSONCodec(&httpReadWriteNopCloser{body, w}) 187 defer codec.Close() 188 189 w.Header().Set("content-type", contentType) 190 srv.ServeSingleRequest(codec, OptionMethodInvocation) 191 } 192 193 // validateRequest returns a non-zero response code and error message if the 194 // request is invalid. 195 func validateRequest(r *http.Request) (int, error) { 196 if r.Method == http.MethodPut || r.Method == http.MethodDelete { 197 return http.StatusMethodNotAllowed, errors.New("method not allowed") 198 } 199 if r.ContentLength > maxHTTPRequestContentLength { 200 err := fmt.Errorf("content length too large (%d>%d)", r.ContentLength, maxHTTPRequestContentLength) 201 return http.StatusRequestEntityTooLarge, err 202 } 203 mt, _, err := mime.ParseMediaType(r.Header.Get("content-type")) 204 if r.Method != http.MethodOptions && (err != nil || mt != contentType) { 205 err := fmt.Errorf("invalid content type, only %s is supported", contentType) 206 return http.StatusUnsupportedMediaType, err 207 } 208 return 0, nil 209 } 210 211 func newCorsHandler(srv *Server, allowedOrigins []string) http.Handler { 212 // disable CORS support if user has not specified a custom CORS configuration 213 if len(allowedOrigins) == 0 { 214 return srv 215 } 216 c := cors.New(cors.Options{ 217 AllowedOrigins: allowedOrigins, 218 AllowedMethods: []string{http.MethodPost, http.MethodGet}, 219 MaxAge: 600, 220 AllowedHeaders: []string{"*"}, 221 }) 222 return c.Handler(srv) 223 } 224 225 // virtualHostHandler is a handler which validates the Host-header of incoming requests. 226 // The virtualHostHandler can prevent DNS rebinding attacks, which do not utilize CORS-headers, 227 // since they do in-domain requests against the RPC api. Instead, we can see on the Host-header 228 // which domain was used, and validate that against a whitelist. 229 type virtualHostHandler struct { 230 vhosts map[string]struct{} 231 next http.Handler 232 } 233 234 // ServeHTTP serves JSON-RPC requests over HTTP, implements http.Handler 235 func (h *virtualHostHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 236 // if r.Host is not set, we can continue serving since a browser would set the Host header 237 if r.Host == "" { 238 h.next.ServeHTTP(w, r) 239 return 240 } 241 host, _, err := net.SplitHostPort(r.Host) 242 if err != nil { 243 // Either invalid (too many colons) or no port specified 244 host = r.Host 245 } 246 if ipAddr := net.ParseIP(host); ipAddr != nil { 247 // It's an IP address, we can serve that 248 h.next.ServeHTTP(w, r) 249 return 250 251 } 252 // Not an ip address, but a hostname. Need to validate 253 if _, exist := h.vhosts["*"]; exist { 254 h.next.ServeHTTP(w, r) 255 return 256 } 257 if _, exist := h.vhosts[host]; exist { 258 h.next.ServeHTTP(w, r) 259 return 260 } 261 http.Error(w, "invalid host specified", http.StatusForbidden) 262 } 263 264 func newVHostHandler(vhosts []string, next http.Handler) http.Handler { 265 vhostMap := make(map[string]struct{}) 266 for _, allowedHost := range vhosts { 267 vhostMap[strings.ToLower(allowedHost)] = struct{}{} 268 } 269 return &virtualHostHandler{vhostMap, next} 270 } 271 272 // allowIPHandler is a handler which only allows certain IP 273 type allowIPHandler struct { 274 allowedIPs map[string]struct{} 275 next http.Handler 276 } 277 278 type ipRange struct { 279 start net.IP 280 end net.IP 281 } 282 283 // inRange - check to see if a given ip address is within a range given 284 func inRange(r ipRange, ipAddress net.IP) bool { 285 // strcmp type byte comparison 286 if bytes.Compare(ipAddress, r.start) >= 0 && bytes.Compare(ipAddress, r.end) < 0 { 287 return true 288 } 289 return false 290 } 291 292 var privateRanges = []ipRange{ 293 { 294 start: net.ParseIP("10.0.0.0"), 295 end: net.ParseIP("10.255.255.255"), 296 }, 297 { 298 start: net.ParseIP("100.64.0.0"), 299 end: net.ParseIP("100.127.255.255"), 300 }, 301 { 302 start: net.ParseIP("172.16.0.0"), 303 end: net.ParseIP("172.31.255.255"), 304 }, 305 { 306 start: net.ParseIP("192.0.0.0"), 307 end: net.ParseIP("192.0.0.255"), 308 }, 309 { 310 start: net.ParseIP("192.168.0.0"), 311 end: net.ParseIP("192.168.255.255"), 312 }, 313 { 314 start: net.ParseIP("198.18.0.0"), 315 end: net.ParseIP("198.19.255.255"), 316 }, 317 } 318 319 // isPrivateSubnet - check to see if this ip is in a private subnet 320 func isPrivateSubnet(ipAddress net.IP) bool { 321 if ipCheck := ipAddress.To4(); ipCheck != nil { 322 // iterate over all our ranges 323 for _, r := range privateRanges { 324 // check if this ip is in a private range 325 if inRange(r, ipAddress) { 326 return true 327 } 328 } 329 return false 330 } 331 if ipCheck := ipAddress.To16(); ipCheck != nil { 332 return ipCheck.IsLinkLocalUnicast() || ipCheck.IsLinkLocalMulticast() 333 } 334 return false 335 } 336 337 func getIP(r *http.Request) string { 338 for _, h := range []string{"X-Forwarded-For", "X-Real-Ip"} { 339 addresses := strings.Split(r.Header.Get(h), ",") 340 // march from right to left until we get a public address 341 // that will be the address right before our proxy. 342 for i := len(addresses) - 1; i >= 0; i-- { 343 // header can contain spaces too, strip those out. 344 ip := strings.TrimSpace(addresses[i]) 345 realIP := net.ParseIP(ip) 346 if !realIP.IsGlobalUnicast() || isPrivateSubnet(realIP) { 347 // bad address, go to next 348 continue 349 } 350 return ip 351 } 352 } 353 remoteAddr, _, err := net.SplitHostPort(r.RemoteAddr) 354 if err != nil { 355 // Either invalid (too many colons) or no port specified 356 remoteAddr = strings.Split(r.RemoteAddr, ":")[0] 357 } 358 if ipAddr := net.ParseIP(remoteAddr); ipAddr != nil { 359 return ipAddr.String() 360 } 361 return "local" 362 } 363 364 // ServeHTTP serves JSON-RPC requests over HTTP, implements http.Handler 365 func (h *allowIPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 366 if _, exist := h.allowedIPs["*"]; exist { 367 log.Debug("bypass -allowip") 368 h.next.ServeHTTP(w, r) 369 return 370 } 371 ip := getIP(r) 372 log.Debug("checking vs allow IPs", "ip", ip) 373 if _, exist := h.allowedIPs[ip]; exist { 374 h.next.ServeHTTP(w, r) 375 return 376 } 377 log.Debug("forbidding rpc access (-allowip flag)", "BadIP", ip) 378 http.Error(w, "", http.StatusForbidden) 379 } 380 381 func newAllowIPHandler(allowIPs []string, next http.Handler) http.Handler { 382 allowIPMap := make(map[string]struct{}) 383 for _, allowedIP := range allowIPs { 384 allowIPMap[allowedIP] = struct{}{} 385 } 386 return &allowIPHandler{allowIPMap, next} 387 }