Skip to content

Commit 180fb75

Browse files
committed
netcat: convert to pan
Add path policy options to command line. Use quicutils.SingleStream, making this incompatible with previous versions. Removed the long list of supported protocols in netcat again -- that was a bit of a brain fart. The delicate handling of the quic streams is enough of a protocol to warrant having a dedicated identifier. Updated netcat QUIC integration tests (dont need the -b now, as both peers can now start transmitting first). Only tangentially related, fix concurrent Read/Close in the udpListenConn.
1 parent 82f3a41 commit 180fb75

File tree

4 files changed

+81
-108
lines changed

4 files changed

+81
-108
lines changed

netcat/main.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ import (
2222
"os"
2323
"os/exec"
2424
"strconv"
25+
"strings"
2526
"sync"
2627
"time"
28+
29+
"github.com/netsec-ethz/scion-apps/pkg/pan"
2730
)
2831

2932
var (
@@ -40,6 +43,10 @@ var (
4043
commandString string
4144

4245
verboseMode bool
46+
47+
interactive bool
48+
sequence string
49+
preference string
4350
)
4451

4552
func printUsage() {
@@ -73,6 +80,11 @@ func main() {
7380
flag.BoolVar(&shutdownAfterEOF, "N", false, "Shutdown the network socket after EOF on the input.")
7481
flag.DurationVar(&shutdownAfterEOFTimeout, "q", 0, "After EOF on stdin, wait the specified number of seconds and then quit. Implies -N.")
7582
flag.StringVar(&commandString, "c", "", "Command")
83+
flag.BoolVar(&interactive, "interactive", false, "Prompt user for interactive path selection")
84+
flag.StringVar(&sequence, "sequence", "", "Sequence of space separated hop predicates to specify path")
85+
flag.StringVar(&preference, "preference", "", "Preference sorting order for paths. "+
86+
"Comma-separated list of available sorting options: "+
87+
strings.Join(pan.AvailablePreferencePolicies, "|"))
7688
flag.BoolVar(&verboseMode, "v", false, "Verbose mode")
7789
flag.Parse()
7890

@@ -115,7 +127,11 @@ func main() {
115127
}
116128
} else {
117129
remoteAddr := tail[0]
118-
conn, err := doDial(remoteAddr)
130+
policy, err := pan.PolicyFromCommandline(sequence, preference, interactive)
131+
if err != nil {
132+
log.Fatal(err)
133+
}
134+
conn, err := doDial(remoteAddr, policy)
119135
if err != nil {
120136
log.Fatal(err)
121137
}
@@ -235,13 +251,13 @@ func pipeConn(conn io.ReadWriteCloser) {
235251
logDebug("Connection closed", "conn", conn)
236252
}
237253

238-
func doDial(remoteAddr string) (io.ReadWriteCloser, error) {
254+
func doDial(remoteAddr string, policy pan.Policy) (io.ReadWriteCloser, error) {
239255
var conn io.ReadWriteCloser
240256
var err error
241257
if udpMode {
242-
conn, err = DoDialUDP(remoteAddr)
258+
conn, err = DoDialUDP(remoteAddr, policy)
243259
} else {
244-
conn, err = DoDialQUIC(remoteAddr)
260+
conn, err = DoDialQUIC(remoteAddr, policy)
245261
}
246262
if err != nil {
247263
return nil, err

netcat/netcat_integration_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,22 +54,22 @@ func TestIntegrationScionNetcatCmd(t *testing.T) {
5454
{
5555
name: "UDP",
5656
message: "Hello UDP World!",
57-
flags: []string{"-u"},
57+
flags: []string{"-b", "-u", "-q", "50ms"},
58+
// NOTE: we need -b as the client does not otherwise send any data to make the "query"
5859
},
5960
}
6061
for _, tc := range cases {
6162
t.Run(tc.name, func(t *testing.T) {
6263
serverPort := "1234"
6364
serverArgs := concat(
6465
tc.flags,
65-
[]string{"-b", "-K", "-c", "echo " + tc.message, "-l", serverPort},
66+
[]string{"-N", "-K", "-c", "echo " + tc.message, "-l", serverPort},
6667
)
67-
// NOTE: we need -b as the client does not otherwise send any data to make the "query"
6868
// BUG: should also work with -k, but doesn't (!?)
6969

7070
clientScriptArgs := concat(
7171
tc.flags,
72-
[]string{"-b", "-q", "10ms", integration.DstAddrPattern + ":" + serverPort},
72+
[]string{integration.DstAddrPattern + ":" + serverPort},
7373
)
7474
in := integration.NewAppsIntegration(netcatCmd, netcatCmd, clientScriptArgs, serverArgs)
7575
in.ClientDelay = 250 * time.Millisecond

netcat/quic.go

Lines changed: 27 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -20,120 +20,62 @@ import (
2020
"io"
2121

2222
"github.com/lucas-clemente/quic-go"
23-
"github.com/netsec-ethz/scion-apps/pkg/appnet/appquic"
23+
"inet.af/netaddr"
24+
25+
"github.com/netsec-ethz/scion-apps/pkg/pan"
26+
"github.com/netsec-ethz/scion-apps/pkg/quicutil"
2427
)
2528

2629
var (
27-
nextProtos = []string{
28-
// generic "proto" that we use e.g. for HTTP-over-QUIC
29-
"raw",
30-
// we accept anything -- use full list of protocol IDs from
31-
// https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
32-
"http/0.9",
33-
"http/1.0",
34-
"http/1.1",
35-
"spdy/1",
36-
"spdy/2",
37-
"spdy/3",
38-
"stun.turn",
39-
"stun.nat-discovery",
40-
"h2",
41-
"h2c",
42-
"webrtc",
43-
"c-webrtc",
44-
"ftp",
45-
"imap",
46-
"pop3",
47-
"managesieve",
48-
"coap",
49-
"xmpp-client",
50-
"xmpp-server",
51-
"acme-tls/1",
52-
"mqtt",
53-
"dot",
54-
"ntske/1",
55-
"sunrpc",
56-
"h3",
57-
"smb",
58-
"irc",
59-
"nntp",
60-
"nnsp",
61-
}
30+
nextProtos = []string{quicutil.SingleStreamProto}
6231
)
6332

64-
type sessConn struct {
65-
sess quic.Session
66-
stream quic.Stream
67-
}
68-
69-
func (conn *sessConn) Read(b []byte) (n int, err error) {
70-
return conn.stream.Read(b)
71-
}
72-
73-
func (conn *sessConn) Write(b []byte) (n int, err error) {
74-
return conn.stream.Write(b)
75-
}
76-
77-
func (conn *sessConn) CloseWrite() error {
78-
return conn.stream.Close()
79-
}
80-
81-
func (conn *sessConn) Close() error {
82-
err := conn.stream.Close()
83-
if err != nil {
84-
return err
85-
}
86-
87-
err = conn.sess.CloseWithError(quic.ApplicationErrorCode(0), "")
88-
if err != nil {
89-
return err
90-
}
91-
return nil
92-
}
93-
9433
// DoListenQUIC listens on a QUIC socket
9534
func DoListenQUIC(port uint16) (chan io.ReadWriteCloser, error) {
96-
listener, err := appquic.ListenPort(
97-
port,
35+
quicListener, err := pan.ListenQUIC(
36+
context.Background(),
37+
netaddr.IPPortFrom(netaddr.IP{}, port),
38+
nil,
9839
&tls.Config{
99-
Certificates: appquic.GetDummyTLSCerts(),
40+
Certificates: quicutil.MustGenerateSelfSignedCert(),
10041
NextProtos: nextProtos,
10142
},
10243
&quic.Config{KeepAlive: true},
10344
)
10445
if err != nil {
10546
return nil, err
10647
}
48+
listener := quicutil.SingleStreamListener{Listener: quicListener}
10749

10850
conns := make(chan io.ReadWriteCloser)
10951
go func() {
110-
for {
111-
sess, err := listener.Accept(context.Background())
112-
if err != nil {
113-
logError("Can't accept listener", "err", err)
114-
continue
115-
}
11652

117-
stream, err := sess.AcceptStream(context.Background())
53+
for {
54+
conn, err := listener.Accept()
11855
if err != nil {
119-
logError("Can't accept stream", "err", err)
56+
logError("Can't accept", "err", err)
12057
continue
12158
}
122-
123-
conns <- &sessConn{
124-
sess: sess,
125-
stream: stream,
126-
}
59+
conns <- conn
12760
}
12861
}()
12962

13063
return conns, nil
13164
}
13265

13366
// DoDialQUIC dials with a QUIC socket
134-
func DoDialQUIC(remoteAddr string) (io.ReadWriteCloser, error) {
135-
sess, err := appquic.Dial(
67+
func DoDialQUIC(remote string, policy pan.Policy) (io.ReadWriteCloser, error) {
68+
remoteAddr, err := pan.ResolveUDPAddr(remote)
69+
if err != nil {
70+
return nil, err
71+
}
72+
sess, err := pan.DialQUIC(
73+
context.Background(),
74+
netaddr.IPPort{},
13675
remoteAddr,
76+
policy,
77+
nil,
78+
pan.MangleSCIONAddr(remote),
13779
&tls.Config{
13880
InsecureSkipVerify: true,
13981
NextProtos: nextProtos,
@@ -144,13 +86,5 @@ func DoDialQUIC(remoteAddr string) (io.ReadWriteCloser, error) {
14486
return nil, err
14587
}
14688

147-
stream, err := sess.OpenStreamSync(context.Background())
148-
if err != nil {
149-
return nil, err
150-
}
151-
152-
return &sessConn{
153-
sess: sess,
154-
stream: stream,
155-
}, nil
89+
return quicutil.NewSingleStream(sess)
15690
}

netcat/udp.go

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,30 @@
1515
package main
1616

1717
import (
18+
"context"
1819
"io"
20+
"sync"
1921

20-
"github.com/netsec-ethz/scion-apps/pkg/appnet"
22+
"inet.af/netaddr"
23+
24+
"github.com/netsec-ethz/scion-apps/pkg/pan"
2125
)
2226

23-
// May not be accessed from multiple threads concurrently, especially Read(...) and Close(...)
2427
type udpListenConn struct {
2528
requests chan<- []byte
2629
responses <-chan int
27-
isClosed bool
30+
mutex sync.Mutex // protects Read's requests/responses channel from concurrent Close
2831
write func(b []byte) (int, error)
2932
close func() error
3033
}
3134

3235
func (conn *udpListenConn) Read(b []byte) (int, error) {
36+
conn.mutex.Lock()
37+
defer conn.mutex.Unlock()
38+
39+
if conn.requests == nil {
40+
return 0, io.EOF
41+
}
3342
conn.requests <- b
3443
return <-conn.responses, nil
3544
}
@@ -39,17 +48,32 @@ func (conn *udpListenConn) Write(b []byte) (int, error) {
3948
}
4049

4150
func (conn *udpListenConn) Close() error {
51+
conn.mutex.Lock()
52+
defer conn.mutex.Unlock()
4253
return conn.close()
4354
}
4455

4556
// DoDialUDP dials with a UDP socket
46-
func DoDialUDP(remote string) (io.ReadWriteCloser, error) {
47-
return appnet.Dial(remote)
57+
func DoDialUDP(remote string, policy pan.Policy) (io.ReadWriteCloser, error) {
58+
remoteAddr, err := pan.ResolveUDPAddr(remote)
59+
if err != nil {
60+
return nil, err
61+
}
62+
conn, err := pan.DialUDP(context.Background(), netaddr.IPPort{}, remoteAddr, policy, nil)
63+
if err != nil {
64+
return nil, err
65+
}
66+
67+
return conn, nil
4868
}
4969

5070
// DoListenUDP listens on a UDP socket
5171
func DoListenUDP(port uint16) (chan io.ReadWriteCloser, error) {
52-
conn, err := appnet.ListenPort(port)
72+
conn, err := pan.ListenUDP(
73+
context.Background(),
74+
netaddr.IPPortFrom(netaddr.IP{}, port),
75+
nil,
76+
)
5377
if err != nil {
5478
return nil, err
5579
}
@@ -84,7 +108,6 @@ func DoListenUDP(port uint16) (chan io.ReadWriteCloser, error) {
84108
conns <- &udpListenConn{
85109
requests: nbufChan,
86110
responses: nrespChan,
87-
isClosed: false,
88111
write: func(b []byte) (n int, err error) {
89112
return conn.WriteTo(b, addr)
90113
},

0 commit comments

Comments
 (0)