Skip to content

Commit 643ea6f

Browse files
committed
docs
1 parent 67c55bd commit 643ea6f

File tree

2 files changed

+232
-2
lines changed

2 files changed

+232
-2
lines changed

README.md

Lines changed: 165 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,74 @@
44
[![Go Reference](https://pkg.go.dev/badge/github.com/tonymet/dualstack.svg)](https://pkg.go.dev/github.com/tonymet/dualstack)
55

66
## Dualstack -- utilities to ease migration to ipv6
7+
We recognize there are still barriers to ipv6 adoption. This project aims to identify anti-patterns blocking ipv6 / dual stack
8+
compatibility like `net.Listen("tcp", "127.0.0.1")` . First , ipv6
9+
linter/analyzer identifies faulty code. dualstack offers a few ipv6-compatible
10+
approaches to secure those interfaces: multilistener to listen to multiple interfaces with a single Accept(), middleware
11+
to block remote http traffic, and firewall to block remote tcp connections.
12+
13+
Now that the utilties are mature, the next step is to expand the lint suite and
14+
enter PRs on open source projects to help improve ipv6 compatibility
15+
16+
## How to Listen Properly to support ipv6 and ipv4 dual stack
17+
18+
* `net.Listen("tcp", ":" + port)` is the preferred dual stack listener on all interfaces. The kernel will handle ipv4 & ipv6
19+
connections. But for loopback services like oauth, this risks exposure to the internet
20+
21+
### To protect a net.Listener, you can wrap with `middleware.FirewallListener`
22+
e.g.
23+
```
24+
l, _ := net.Listen("tcp", ":" + port)
25+
protectedListener := middleware.FirewallListener{l}
26+
//
27+
for{
28+
// use as usual
29+
conn, err := protectedListener.Accept()
30+
if err == net.errClosed{
31+
return
32+
} else if err != nil{
33+
// connection was blocked
34+
continue
35+
}
36+
go handleConnection(conn)
37+
}
38+
```
39+
40+
### To listen to all localhost interfaces , use multilistener
41+
42+
```
43+
ml, err := multilistener.NewLocalLoopback()
44+
if err != nil{
45+
panic(err)
46+
}
47+
// http will serve on [::1] and 127.0.0.1
48+
http.Serve(ml, nil)
49+
```
50+
51+
### How to Protect an Existing http.Server
52+
`LocalOnlyMiddleware` adds a remote-address filter before your handler. Any remote address will receive 403 / unauthorized.
753

8-
### Overview
54+
55+
```
56+
func ExampleLocalOnlyMiddleware() {
57+
nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
58+
w.WriteHeader(http.StatusOK)
59+
w.Write([]byte("Allowed"))
60+
})
61+
protectedHandler := LocalOnlyMiddleware(nextHandler)
62+
// for common apps use http.Handle("/", protectedHandler)
63+
ts := httptest.NewServer(protectedHandler)
64+
defer ts.Close()
65+
66+
```
67+
68+
## Why Now?
69+
70+
Developers are familiar with ipv4 as a stable and secure approach. Local oauth
71+
services are mature. But With IPv4 address exhaustion accelerating, ipv6 compatibility
72+
is more urgent now than it has been in the past.
73+
74+
## Package Overview
975

1076
* multilistener -- listen on multiple local loopback interfaces with multilistener.NewLocalLoopback()
1177
* middleware -- block remote connections on net.Listener and http.Server. see middleware.FirewallListener and middleware.LocalOnlyMiddleware
@@ -446,4 +512,102 @@ import "github.com/tonymet/dualstack/internal/bad-go-code"
446512

447513

448514

515+
# testing
516+
517+
```go
518+
import "github.com/tonymet/dualstack/middleware/testing"
519+
```
520+
521+
middleware/testing package with mock interfaces for testing net.Listener
522+
523+
## Index
524+
525+
- [type MockConn](<#MockConn>)
526+
- [func \(m \*MockConn\) Close\(\) error](<#MockConn.Close>)
527+
- [func \(m \*MockConn\) RemoteAddr\(\) net.Addr](<#MockConn.RemoteAddr>)
528+
- [type MockListener](<#MockListener>)
529+
- [func NewMockListener\(\) \*MockListener](<#NewMockListener>)
530+
- [func \(m \*MockListener\) Accept\(\) \(net.Conn, error\)](<#MockListener.Accept>)
531+
- [func \(m \*MockListener\) Addr\(\) net.Addr](<#MockListener.Addr>)
532+
- [func \(m \*MockListener\) Close\(\) error](<#MockListener.Close>)
533+
534+
535+
<a name="MockConn"></a>
536+
## type MockConn
537+
538+
MockConn is a fake net.Conn for testing purposes.
539+
540+
```go
541+
type MockConn struct {
542+
net.Conn
543+
// contains filtered or unexported fields
544+
}
545+
```
546+
547+
<a name="MockConn.Close"></a>
548+
### func \(\*MockConn\) Close
549+
550+
```go
551+
func (m *MockConn) Close() error
552+
```
553+
554+
555+
556+
<a name="MockConn.RemoteAddr"></a>
557+
### func \(\*MockConn\) RemoteAddr
558+
559+
```go
560+
func (m *MockConn) RemoteAddr() net.Addr
561+
```
562+
563+
564+
565+
<a name="MockListener"></a>
566+
## type MockListener
567+
568+
MockListener is a fake net.Listener for testing purposes.
569+
570+
```go
571+
type MockListener struct {
572+
net.Listener
573+
// contains filtered or unexported fields
574+
}
575+
```
576+
577+
<a name="NewMockListener"></a>
578+
### func NewMockListener
579+
580+
```go
581+
func NewMockListener() *MockListener
582+
```
583+
584+
585+
586+
<a name="MockListener.Accept"></a>
587+
### func \(\*MockListener\) Accept
588+
589+
```go
590+
func (m *MockListener) Accept() (net.Conn, error)
591+
```
592+
593+
594+
595+
<a name="MockListener.Addr"></a>
596+
### func \(\*MockListener\) Addr
597+
598+
```go
599+
func (m *MockListener) Addr() net.Addr
600+
```
601+
602+
603+
604+
<a name="MockListener.Close"></a>
605+
### func \(\*MockListener\) Close
606+
607+
```go
608+
func (m *MockListener) Close() error
609+
```
610+
611+
612+
449613
Generated by [gomarkdoc](<https://github.com/princjef/gomarkdoc>)

header.in

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,74 @@
22
[![Go Reference](https://pkg.go.dev/badge/github.com/tonymet/dualstack.svg)](https://pkg.go.dev/github.com/tonymet/dualstack)
33

44
## Dualstack -- utilities to ease migration to ipv6
5+
We recognize there are still barriers to ipv6 adoption. This project aims to identify anti-patterns blocking ipv6 / dual stack
6+
compatibility like `net.Listen("tcp", "127.0.0.1")` . First , ipv6
7+
linter/analyzer identifies faulty code. dualstack offers a few ipv6-compatible
8+
approaches to secure those interfaces: multilistener to listen to multiple interfaces with a single Accept(), middleware
9+
to block remote http traffic, and firewall to block remote tcp connections.
510

6-
### Overview
11+
Now that the utilties are mature, the next step is to expand the lint suite and
12+
enter PRs on open source projects to help improve ipv6 compatibility
13+
14+
## How to Listen Properly to support ipv6 and ipv4 dual stack
15+
16+
* `net.Listen("tcp", ":" + port)` is the preferred dual stack listener on all interfaces. The kernel will handle ipv4 & ipv6
17+
connections. But for loopback services like oauth, this risks exposure to the internet
18+
19+
### To protect a net.Listener, you can wrap with `middleware.FirewallListener`
20+
e.g.
21+
```
22+
l, _ := net.Listen("tcp", ":" + port)
23+
protectedListener := middleware.FirewallListener{l}
24+
//
25+
for{
26+
// use as usual
27+
conn, err := protectedListener.Accept()
28+
if err == net.errClosed{
29+
return
30+
} else if err != nil{
31+
// connection was blocked
32+
continue
33+
}
34+
go handleConnection(conn)
35+
}
36+
```
37+
38+
### To listen to all localhost interfaces , use multilistener
39+
40+
```
41+
ml, err := multilistener.NewLocalLoopback()
42+
if err != nil{
43+
panic(err)
44+
}
45+
// http will serve on [::1] and 127.0.0.1
46+
http.Serve(ml, nil)
47+
```
48+
49+
### How to Protect an Existing http.Server
50+
`LocalOnlyMiddleware` adds a remote-address filter before your handler. Any remote address will receive 403 / unauthorized.
51+
52+
53+
```
54+
func ExampleLocalOnlyMiddleware() {
55+
nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
56+
w.WriteHeader(http.StatusOK)
57+
w.Write([]byte("Allowed"))
58+
})
59+
protectedHandler := LocalOnlyMiddleware(nextHandler)
60+
// for common apps use http.Handle("/", protectedHandler)
61+
ts := httptest.NewServer(protectedHandler)
62+
defer ts.Close()
63+
64+
```
65+
66+
## Why Now?
67+
68+
Developers are familiar with ipv4 as a stable and secure approach. Local oauth
69+
services are mature. But With IPv4 address exhaustion accelerating, ipv6 compatibility
70+
is more urgent now than it has been in the past.
71+
72+
## Package Overview
773

874
* multilistener -- listen on multiple local loopback interfaces with multilistener.NewLocalLoopback()
975
* middleware -- block remote connections on net.Listener and http.Server. see middleware.FirewallListener and middleware.LocalOnlyMiddleware

0 commit comments

Comments
 (0)