github.com/influx6/npkg@v0.8.8/nip/nip.go (about)

     1  package nip
     2  
     3  import (
     4  	"bytes"
     5  	"net"
     6  	"net/http"
     7  	"strings"
     8  
     9  	"github.com/influx6/npkg/nerror"
    10  )
    11  
    12  var DefaultSubnet = PrivateSubnets{
    13  	IpRange{
    14  		Start: net.ParseIP("10.0.0.0"),
    15  		End:   net.ParseIP("10.255.255.255"),
    16  	},
    17  	IpRange{
    18  		Start: net.ParseIP("100.64.0.0"),
    19  		End:   net.ParseIP("100.127.255.255"),
    20  	},
    21  	IpRange{
    22  		Start: net.ParseIP("172.16.0.0"),
    23  		End:   net.ParseIP("172.31.255.255"),
    24  	},
    25  	IpRange{
    26  		Start: net.ParseIP("192.0.0.0"),
    27  		End:   net.ParseIP("192.0.0.255"),
    28  	},
    29  	IpRange{
    30  		Start: net.ParseIP("192.168.0.0"),
    31  		End:   net.ParseIP("192.168.255.255"),
    32  	},
    33  	IpRange{
    34  		Start: net.ParseIP("198.18.0.0"),
    35  		End:   net.ParseIP("198.19.255.255"),
    36  	},
    37  }
    38  
    39  //IpRange - a structure that holds the Start and End of a range of ip addresses
    40  type IpRange struct {
    41  	Start net.IP
    42  	End   net.IP
    43  }
    44  
    45  // InRange - check to see if a given ip address is within a range given
    46  func InRange(r IpRange, ipAddress net.IP) bool {
    47  	// strcmp type byte comparison
    48  	if bytes.Compare(ipAddress, r.Start) >= 0 && bytes.Compare(ipAddress, r.End) < 0 {
    49  		return true
    50  	}
    51  	return false
    52  }
    53  
    54  type PrivateSubnets []IpRange
    55  
    56  func (subnet *PrivateSubnets) ParseRequestIP(r *http.Request) (net.Addr, error) {
    57  	for _, h := range []string{"X-Forwarded-For", "X-Real-Ip"} {
    58  		addresses := strings.Split(r.Header.Get(h), ",")
    59  		// march from right to left until we get a public address
    60  		// that will be the address right before our proxy.
    61  		for i := len(addresses) - 1; i >= 0; i-- {
    62  			ip := strings.TrimSpace(addresses[i])
    63  			// header can contain spaces too, strip those out.
    64  			realIP := net.ParseIP(ip)
    65  			if !realIP.IsGlobalUnicast() || IsPrivateSubnet(*subnet, realIP) {
    66  				// bad address, go to next
    67  				continue
    68  			}
    69  
    70  			var parsedIP, parseErr = net.ResolveIPAddr("tcp", realIP.String())
    71  			if parseErr != nil {
    72  				return nil, nerror.WrapOnly(parseErr)
    73  			}
    74  			return parsedIP, nil
    75  		}
    76  	}
    77  
    78  	var ip, _, err = net.SplitHostPort(r.RemoteAddr)
    79  	if err != nil {
    80  		return nil, nerror.WrapOnly(err)
    81  	}
    82  
    83  	var parsedIP, parseErr = net.ResolveIPAddr("tcp", ip)
    84  	if parseErr != nil {
    85  		return nil, nerror.WrapOnly(parseErr)
    86  	}
    87  
    88  	return parsedIP, nil
    89  }
    90  
    91  // IsPrivateSubnet - check to see if this ip is in a private subnet
    92  func IsPrivateSubnet(subnet PrivateSubnets, ipAddress net.IP) bool {
    93  	// my use case is only concerned with ipv4 atm
    94  	if ipCheck := ipAddress.To4(); ipCheck != nil {
    95  		// iterate over all our ranges
    96  		for _, r := range subnet {
    97  			// check if this ip is in a private range
    98  			if InRange(r, ipAddress) {
    99  				return true
   100  			}
   101  		}
   102  	}
   103  	return false
   104  }