gitlab.com/ignitionrobotics/web/ign-go@v1.0.0-rc4/ip_finder.go (about)

     1  package ign
     2  
     3  // Code originally taken from
     4  // https://husobee.github.io/golang/ip-address/2015/12/17/remote-ip-go.html
     5  
     6  import (
     7  	"bytes"
     8  	"net"
     9  	"net/http"
    10  	"strings"
    11  )
    12  
    13  // ipRange is a structure that holds the start and end of a range of
    14  // ip addresses
    15  type ipRange struct {
    16  	start net.IP
    17  	end   net.IP
    18  }
    19  
    20  // private ranges lists IP ranges that are considered private or local
    21  // addresses
    22  var privateRanges = []ipRange{
    23  	{
    24  		start: net.ParseIP("10.0.0.0"),
    25  		end:   net.ParseIP("10.255.255.255"),
    26  	},
    27  	{
    28  		start: net.ParseIP("100.64.0.0"),
    29  		end:   net.ParseIP("100.127.255.255"),
    30  	},
    31  	{
    32  		start: net.ParseIP("172.16.0.0"),
    33  		end:   net.ParseIP("172.31.255.255"),
    34  	},
    35  	{
    36  		start: net.ParseIP("192.0.0.0"),
    37  		end:   net.ParseIP("192.0.0.255"),
    38  	},
    39  	{
    40  		start: net.ParseIP("192.168.0.0"),
    41  		end:   net.ParseIP("192.168.255.255"),
    42  	},
    43  	{
    44  		start: net.ParseIP("198.18.0.0"),
    45  		end:   net.ParseIP("198.19.255.255"),
    46  	},
    47  }
    48  
    49  // inRange checks to see if a given ip address is within a range given
    50  func inRange(r ipRange, ipAddress net.IP) bool {
    51  	// strcmp type byte comparison
    52  	if bytes.Compare(ipAddress, r.start) >= 0 &&
    53  		bytes.Compare(ipAddress, r.end) < 0 {
    54  		return true
    55  	}
    56  	return false
    57  }
    58  
    59  // isPrivateSubnet checks to see if this ip is in a private subnet
    60  func isPrivateSubnet(ipAddress net.IP) bool {
    61  	// my use case is only concerned with ipv4 atm
    62  	if ipCheck := ipAddress.To4(); ipCheck != nil {
    63  		// iterate over all our ranges
    64  		for _, r := range privateRanges {
    65  			// check if this ip is in a private range
    66  			if inRange(r, ipAddress) {
    67  				return true
    68  			}
    69  		}
    70  	}
    71  	return false
    72  }
    73  
    74  /////////////////////////////////////////////////
    75  /// getIPAddress searches, from right to left, for a valid IP address in a
    76  /// request.
    77  func getIPAddress(r *http.Request) string {
    78  
    79  	// Search over possible headers.
    80  	for _, h := range []string{"X-Forwarded-For", "X-Real-Ip"} {
    81  
    82  		// Number of addresses in the header
    83  		addresses := strings.Split(r.Header.Get(h), ",")
    84  
    85  		// March from right to left until we get a public address
    86  		// that will be the address right before our proxy.
    87  		for i := len(addresses) - 1; i >= 0; i-- {
    88  			ip := strings.TrimSpace(addresses[i])
    89  
    90  			// header can contain spaces too, strip those out.
    91  			realIP := net.ParseIP(ip)
    92  
    93  			if !realIP.IsGlobalUnicast() || isPrivateSubnet(realIP) {
    94  				// bad address, go to next
    95  				continue
    96  			}
    97  			return ip
    98  		}
    99  	}
   100  	return ""
   101  }