forked from tinkerbell/smee
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request tinkerbell#451 from jacobweinstock/remove-dep-pack…
…ethost Remove github.com/packethost/xff dependency: ## Description <!--- Please describe what this PR is going to change --> This repo is not maintained. Also, add license header for code copied from the no longer maintainer github.com/equinix-labs/otel-init-go repo. ## Why is this needed <!--- Link to issue you have raised --> Fixes: # ## How Has This Been Tested? <!--- Please describe in detail how you tested your changes. --> <!--- Include details of your testing environment, and the tests you ran to --> <!--- see how your change affects other areas of the code, etc. --> ## How are existing users impacted? What migration steps/scripts do we need? <!--- Fixes a bug, unblocks installation, removes a component of the stack etc --> <!--- Requires a DB migration script, etc. --> ## Checklist: I have: - [ ] updated the documentation and/or roadmap (if required) - [ ] added unit or e2e tests - [ ] provided instructions on how to upgrade
- Loading branch information
Showing
6 changed files
with
328 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/* | ||
https://github.com/sebest/xff | ||
Copyright (c) 2015 Sebastien Estienne ([email protected]) | ||
Permission is hereby granted, free of charge, to any person obtaining | ||
a copy of this software and associated documentation files (the | ||
"Software"), to deal in the Software without restriction, including | ||
without limitation the rights to use, copy, modify, merge, publish, | ||
distribute, sublicense, and/or sell copies of the Software, and to | ||
permit persons to whom the Software is furnished to do so, subject to | ||
the following conditions: | ||
The above copyright notice and this permission notice shall be | ||
included in all copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
*/ | ||
package http | ||
|
||
import ( | ||
"net" | ||
"net/http" | ||
"strings" | ||
) | ||
|
||
// xffOptions is a configuration container to setup the XFF middleware. | ||
type xffOptions struct { | ||
// AllowedSubnets is a list of Subnets from which we will accept the | ||
// X-Forwarded-For header. | ||
// If this list is empty we will accept every Subnets (default). | ||
AllowedSubnets []string | ||
// Debugging flag adds additional output to debug server side XFF issues. | ||
Debug bool | ||
} | ||
|
||
// xff http handler. | ||
type xff struct { | ||
// Set to true if all IPs or Subnets are allowed. | ||
allowAll bool | ||
// List of IP subnets that are allowed. | ||
allowedMasks []net.IPNet | ||
} | ||
|
||
// New creates a new XFF handler with the provided options. | ||
func newXFF(options xffOptions) (*xff, error) { | ||
allowedMasks, err := toMasks(options.AllowedSubnets) | ||
if err != nil { | ||
return nil, err | ||
} | ||
xff := &xff{ | ||
allowAll: len(options.AllowedSubnets) == 0, | ||
allowedMasks: allowedMasks, | ||
} | ||
|
||
return xff, nil | ||
} | ||
|
||
// Handler updates RemoteAdd from X-Fowarded-For Headers. | ||
func (xff *xff) Handler(h http.Handler) http.Handler { | ||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
r.RemoteAddr = getRemoteAddrIfAllowed(r, xff.allowed) | ||
h.ServeHTTP(w, r) | ||
}) | ||
} | ||
|
||
// getRemoteAddrIfAllowed parses the given request, resolves the X-Forwarded-For header | ||
// and returns the resolved remote address if allowed. | ||
func getRemoteAddrIfAllowed(r *http.Request, allowed func(sip string) bool) string { | ||
if xffh := r.Header.Get("X-Forwarded-For"); xffh != "" { | ||
if sip, sport, err := net.SplitHostPort(r.RemoteAddr); err == nil && sip != "" { | ||
if allowed(sip) { | ||
if xip := parse(xffh, allowed); xip != "" { | ||
return net.JoinHostPort(xip, sport) | ||
} | ||
} | ||
} | ||
} | ||
return r.RemoteAddr | ||
} | ||
|
||
// parse parses the value of the X-Forwarded-For Header and returns the IP address. | ||
func parse(ipList string, allowed func(string) bool) string { | ||
ips := strings.Split(ipList, ",") | ||
if len(ips) == 0 { | ||
return "" | ||
} | ||
|
||
// simple case of only 1 proxy | ||
if len(ips) == 1 { | ||
ip := strings.TrimSpace(ips[0]) | ||
if net.ParseIP(ip) != nil { | ||
return ip | ||
} | ||
return "" | ||
} | ||
|
||
// multiple proxies | ||
// common form of X-F-F is: client, proxy1, proxy2, ... proxyN-1 | ||
// so we verify backwards and return the first unallowed/untrusted proxy | ||
lastIP := "" | ||
for i := len(ips) - 1; i >= 0; i-- { | ||
ip := strings.TrimSpace(ips[i]) | ||
if net.ParseIP(ip) == nil { | ||
break | ||
} | ||
lastIP = ip | ||
if !allowed(ip) { | ||
break | ||
} | ||
} | ||
return lastIP | ||
} | ||
|
||
// converts a list of subnets' string to a list of net.IPNet. | ||
func toMasks(ips []string) (masks []net.IPNet, err error) { | ||
for _, cidr := range ips { | ||
var network *net.IPNet | ||
_, network, err = net.ParseCIDR(cidr) | ||
if err != nil { | ||
return | ||
} | ||
masks = append(masks, *network) | ||
} | ||
return | ||
} | ||
|
||
// checks that the IP is allowed. | ||
func (xff *xff) allowed(sip string) bool { | ||
if xff.allowAll { | ||
return true | ||
} else if ip := net.ParseIP(sip); ip != nil && ipInMasks(ip, xff.allowedMasks) { | ||
return true | ||
} | ||
return false | ||
} | ||
|
||
// checks if a net.IP is in a list of net.IPNet. | ||
func ipInMasks(ip net.IP, masks []net.IPNet) bool { | ||
for _, mask := range masks { | ||
if mask.Contains(ip) { | ||
return true | ||
} | ||
} | ||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
/* | ||
https://github.com/sebest/xff | ||
Copyright (c) 2015 Sebastien Estienne ([email protected]) | ||
Permission is hereby granted, free of charge, to any person obtaining | ||
a copy of this software and associated documentation files (the | ||
"Software"), to deal in the Software without restriction, including | ||
without limitation the rights to use, copy, modify, merge, publish, | ||
distribute, sublicense, and/or sell copies of the Software, and to | ||
permit persons to whom the Software is furnished to do so, subject to | ||
the following conditions: | ||
The above copyright notice and this permission notice shall be | ||
included in all copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
*/ | ||
package http | ||
|
||
import ( | ||
"net" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestParse_none(t *testing.T) { | ||
res := parse("", nil) | ||
assert.Equal(t, "", res) | ||
} | ||
|
||
func allowAll(string) bool { return true } | ||
|
||
func TestParse_localhost(t *testing.T) { | ||
res := parse("127.0.0.1", allowAll) | ||
assert.Equal(t, "127.0.0.1", res) | ||
} | ||
|
||
func TestParse_invalid(t *testing.T) { | ||
res := parse("invalid", allowAll) | ||
assert.Equal(t, "", res) | ||
} | ||
|
||
func TestParse_invalid_sioux(t *testing.T) { | ||
res := parse("123#1#2#3", allowAll) | ||
assert.Equal(t, "", res) | ||
} | ||
|
||
func TestParse_invalid_private_lookalike(t *testing.T) { | ||
res := parse("102.3.2.1", allowAll) | ||
assert.Equal(t, "102.3.2.1", res) | ||
} | ||
|
||
func TestParse_valid(t *testing.T) { | ||
res := parse("68.45.152.220", allowAll) | ||
assert.Equal(t, "68.45.152.220", res) | ||
} | ||
|
||
func TestParse_multi_first(t *testing.T) { | ||
res := parse("12.13.14.15, 68.45.152.220", allowAll) | ||
assert.Equal(t, "12.13.14.15", res) | ||
} | ||
|
||
func TestParse_multi_with_invalid(t *testing.T) { | ||
res := parse("invalid, 190.57.149.90", allowAll) | ||
assert.Equal(t, "190.57.149.90", res) | ||
} | ||
|
||
func TestParse_multi_with_invalid2(t *testing.T) { | ||
res := parse("190.57.149.90, invalid", allowAll) | ||
assert.Equal(t, "", res) | ||
} | ||
|
||
func TestParse_multi_with_invalid_sioux(t *testing.T) { | ||
res := parse("190.57.149.90, 123#1#2#3", allowAll) | ||
assert.Equal(t, "", res) | ||
} | ||
|
||
func TestParse_ipv6_with_port(t *testing.T) { | ||
res := parse("2604:2000:71a9:bf00:f178:a500:9a2d:670d", allowAll) | ||
assert.Equal(t, "2604:2000:71a9:bf00:f178:a500:9a2d:670d", res) | ||
} | ||
|
||
func TestToMasks_empty(t *testing.T) { | ||
ips := []string{} | ||
masks, err := toMasks(ips) | ||
assert.Empty(t, masks) | ||
assert.Nil(t, err) | ||
} | ||
|
||
func TestToMasks(t *testing.T) { | ||
ips := []string{"127.0.0.1/32", "10.0.0.0/8"} | ||
masks, err := toMasks(ips) | ||
_, ipnet1, _ := net.ParseCIDR("127.0.0.1/32") | ||
_, ipnet2, _ := net.ParseCIDR("10.0.0.0/8") | ||
assert.Equal(t, []net.IPNet{*ipnet1, *ipnet2}, masks) | ||
assert.Nil(t, err) | ||
} | ||
|
||
func TestToMasks_error(t *testing.T) { | ||
ips := []string{"error"} | ||
masks, err := toMasks(ips) | ||
assert.Empty(t, masks) | ||
assert.Equal(t, &net.ParseError{Type: "CIDR address", Text: "error"}, err) | ||
} | ||
|
||
func TestAllowed_all(t *testing.T) { | ||
m, _ := newXFF(xffOptions{ | ||
AllowedSubnets: []string{}, | ||
}) | ||
assert.True(t, m.allowed("127.0.0.1")) | ||
} | ||
|
||
func TestAllowed_yes(t *testing.T) { | ||
m, _ := newXFF(xffOptions{ | ||
AllowedSubnets: []string{"127.0.0.0/16"}, | ||
}) | ||
assert.True(t, m.allowed("127.0.0.1")) | ||
|
||
m, _ = newXFF(xffOptions{ | ||
AllowedSubnets: []string{"127.0.0.1/32"}, | ||
}) | ||
assert.True(t, m.allowed("127.0.0.1")) | ||
} | ||
|
||
func TestAllowed_no(t *testing.T) { | ||
m, _ := newXFF(xffOptions{ | ||
AllowedSubnets: []string{"127.0.0.0/16"}, | ||
}) | ||
assert.False(t, m.allowed("127.1.0.1")) | ||
|
||
m, _ = newXFF(xffOptions{ | ||
AllowedSubnets: []string{"127.0.0.1/32"}, | ||
}) | ||
assert.False(t, m.allowed("127.0.0.2")) | ||
} | ||
|
||
func TestParseUnallowedMidway(t *testing.T) { | ||
m, _ := newXFF(xffOptions{ | ||
AllowedSubnets: []string{"127.0.0.0/16"}, | ||
}) | ||
res := parse("1.1.1.1, 8.8.8.8, 127.0.0.1, 127.0.0.2", m.allowed) | ||
assert.Equal(t, "8.8.8.8", res) | ||
} | ||
|
||
func TestParseMany(t *testing.T) { | ||
m, _ := newXFF(xffOptions{ | ||
AllowedSubnets: []string{"127.0.0.0/16"}, | ||
}) | ||
res := parse("1.1.1.1, 127.0.0.1, 127.0.0.2, 127.0.0.3", m.allowed) | ||
assert.Equal(t, "1.1.1.1", res) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters