perkeep/internal/netutil/ident_test.go

249 lines
8.8 KiB
Go

/*
Copyright 2011 The Perkeep Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package netutil
import (
"fmt"
"io"
"net"
"net/http"
"net/http/httptest"
"os"
"runtime"
"strings"
"testing"
"time"
)
func TestLocalIPv4(t *testing.T) {
// Start listening on localhost IPv4, on some port.
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
testLocalListener(t, ln)
}
func TestLocalIPv6(t *testing.T) {
ln, err := net.Listen("tcp", "[::1]:0")
if err != nil {
t.Logf("skipping IPv6 test; not supported on host machine?")
return
}
testLocalListener(t, ln)
}
func testLocalListener(t *testing.T, ln net.Listener) {
defer ln.Close()
// Accept a connection, run ConnUserId (what we're testing), and
// send its result on c.
type uidErr struct {
uid int
err error
}
c := make(chan uidErr, 2)
go func() {
conn, err := ln.Accept()
if err != nil {
c <- uidErr{0, err}
}
uid, err := ConnUserid(conn)
c <- uidErr{uid, err}
}()
// Connect to our dummy server. Keep the connection open until
// the test is done.
donec := make(chan bool)
defer close(donec)
go func() {
c, err := net.Dial("tcp", ln.Addr().String())
if err != nil {
return
}
<-donec
c.Close()
}()
select {
case r := <-c:
if r.err != nil {
if r.err == ErrUnsupportedOS {
t.Skipf("Skipping test; not implemented on " + runtime.GOOS)
}
t.Fatal(r.err)
}
if r.uid != os.Getuid() {
t.Errorf("got uid %d; want %d", r.uid, os.Getuid())
}
case <-time.After(3 * time.Second):
t.Fatal("timeout")
}
}
func TestHTTPAuth(t *testing.T) {
var ts *httptest.Server
ts = httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
from, err := HostPortToIP(r.RemoteAddr, nil)
if err != nil {
t.Fatal(err)
}
to := ts.Listener.Addr()
uid, err := AddrPairUserid(from, to)
if err != nil {
fmt.Fprintf(rw, "ERR: %v", err)
return
}
fmt.Fprintf(rw, "uid=%d", uid)
}))
defer ts.Close()
res, err := http.Get(ts.URL)
if err != nil {
t.Fatal(err)
}
body, err := io.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
if g, e := string(body), fmt.Sprintf("uid=%d", os.Getuid()); g != e {
if g == "ERR: "+ErrUnsupportedOS.Error() {
t.Skipf("Skipping test; not implemented on " + runtime.GOOS)
}
t.Errorf("got body %q; want %q", g, e)
}
}
func testUIDFromUsername(username string) (int, error) {
switch username {
case "really-long-user":
return 1000, nil
case "root":
return 0, nil
}
panic("Unhandled username specified in test")
}
func TestParseFreeBSDSockstat(t *testing.T) {
uidFromUsername = testUIDFromUsername
pairs := []struct {
uid int
lip, rip net.IP
lport, rport int
}{
{
// "really-long-user"
uid: 1000,
lip: net.ParseIP("192.168.123.5"), lport: 8000,
rip: net.ParseIP("192.168.123.21"), rport: 49826,
},
{
// "really-long-user"
uid: 1000,
lip: net.ParseIP("192.168.123.5"), lport: 9000,
rip: net.ParseIP("192.168.123.21"), rport: 49866,
},
{
// "root"
uid: 0,
lip: net.ParseIP("192.168.123.5"), lport: 22,
rip: net.ParseIP("192.168.123.21"), rport: 49747,
},
}
for _, p := range pairs {
uid, err := uidFromSockstatReader(p.lip, p.lport, p.rip, p.rport, strings.NewReader(sockstatPtcp))
if err != nil {
t.Error(err)
}
if p.uid != uid {
t.Error("Got", uid, "want", p.uid)
}
}
}
func TestParseLinuxTCPStat4(t *testing.T) {
lip, lport := net.ParseIP("67.218.110.129"), 43436
rip, rport := net.ParseIP("207.7.148.195"), 80
// 816EDA43:A9AC C39407CF:0050
// 43436 80
uid, err := uidFromProcReader(lip, lport, rip, rport, strings.NewReader(tcpstat4))
if err != nil {
t.Error(err)
}
if e, g := 61652, uid; e != g {
t.Errorf("expected uid %d, got %d", e, g)
}
}
var tcpstat4 = ` sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 0100007F:C204 00000000:0000 0A 00000000:00000000 00:00000000 00000000 61652 0 8722922 1 ffff880036b36180 300 0 0 2 -1
1: 0100007F:0CEA 00000000:0000 0A 00000000:00000000 00:00000000 00000000 120 0 5714729 1 ffff880036b35480 300 0 0 2 -1
2: 0100007F:2BCB 00000000:0000 0A 00000000:00000000 00:00000000 00000000 65534 0 7381 1 ffff880136370000 300 0 0 2 -1
3: 0100007F:13AD 00000000:0000 0A 00000000:00000000 00:00000000 00000000 61652 0 4846349 1 ffff880123eb5480 300 0 0 2 -1
4: 00000000:0050 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 8307 1 ffff880123eb0d00 300 0 0 2 -1
5: 00000000:0071 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 8558503 1 ffff88001a242080 300 0 0 2 -1 6: 0100007F:7533 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 8686 1 ffff880136371380 300 0 0 2 -1
7: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 6015 1 ffff880123eb0680 300 0 0 2 -1
8: 0100007F:0277 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 8705543 1 ffff88001a242d80 300 0 0 2 -1
9: 816EDA43:D4DC 35E07D4A:01BB 01 00000000:00000000 02:00000E25 00000000 61652 0 8720744 2 ffff88001a243a80 346 4 24 3 2
10: 0100007F:C204 0100007F:D981 01 00000000:00000000 00:00000000 00000000 61652 0 8722934 1 ffff88006712a700 21 4 30 5 -1
11: 816EDA43:A9AC C39407CF:0050 01 00000000:00000000 00:00000000 00000000 61652 0 8754873 1 ffff88006712db00 27 0 0 3 -1
12: 816EDA43:AFEF 51357D4A:01BB 01 00000000:00000000 02:00000685 00000000 61652 0 8752937 2 ffff880136375480 87 4 2 4 -1
13: 0100007F:D981 0100007F:C204 01 00000000:00000000 00:00000000 00000000 61652 0 8722933 1 ffff880036b30d00 21 4 0 3 -1
`
// Output of 'sockstat -Ptcp'. User 'really-long-user' running two instances
// of nc copied to 'really-only-process-name' and 'spc in name' run with -l
// 8000 and -l 9000 respectively. Two connections were then open from
// 192.167.123.21 using 'nc 192.168.123.5 8000' and 'nc 192.168.123.5 9000'.
var sockstatPtcp = `
sockstat -Ptcp
USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS
really-long-user spc in nam63210 3 tcp4 *:9000 *:*
really-long-user spc in nam63210 4 tcp4 192.168.123.5:9000192.168.123.21:49866
www nginx 62982 7 tcp4 *:80 *:*
www nginx 62982 8 tcp6 *:80 *:*
really-long-user really-lon62928 3 tcp4 *:8000 *:*
really-long-user really-lon62928 4 tcp4 192.168.123.5:8000192.168.123.21:49826
root sshd 62849 5 tcp4 192.168.123.5:22 192.168.123.21:49819
root sshd 61819 5 tcp4 192.168.123.5:22 192.168.123.21:49747
camlistore sshd 61746 5 tcp4 192.168.123.5:22 192.168.123.21:49739
root sshd 61744 5 tcp4 192.168.123.5:22 192.168.123.21:49739
camlistore camlistore10941 7 tcp4 6 *:3179 *:*
camlistore sshd 91620 5 tcp4 192.168.123.5:22 192.168.123.2:13404
root sshd 91618 5 tcp4 192.168.123.5:22 192.168.123.2:13404
root sshd 2309 4 tcp6 *:22 *:*
root sshd 2309 5 tcp4 *:22 *:*
root nginx 2152 7 tcp4 *:80 *:*
root nginx 2152 8 tcp6 *:80 *:*
root python2.7 2076 3 tcp4 127.0.0.1:9042 *:*
root python2.7 2076 6 tcp4 127.0.0.1:9042 127.0.0.1:51930
root python2.7 2076 7 tcp4 127.0.0.1:9042 127.0.0.1:20433
root python2.7 2076 8 tcp4 127.0.0.1:9042 127.0.0.1:55807
root rpc.statd 1630 5 tcp6 *:664 *:*
root rpc.statd 1630 7 tcp4 *:664 *:*
root nfsd 1618 5 tcp4 *:2049 *:*
root nfsd 1618 6 tcp6 *:2049 *:*
root mountd 1604 6 tcp6 *:792 *:*
root mountd 1604 8 tcp4 *:792 *:*
root rpcbind 1600 8 tcp6 *:111 *:*
root rpcbind 1600 11 tcp4 *:111 *:*
? ? ? ? tcp4 *:895 *:*
? ? ? ? tcp6 *:777 *:*
`