-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathudp4-reflect.go
131 lines (110 loc) · 2.42 KB
/
udp4-reflect.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
* Synopsis:
* Listen on udp4 port and reflect incoming packets to ip4s.
* Usage:
* udp4-reflect <in-ip4:port> <out1-ip4:port> <out2-ip4:port> ...
* udp4-reflect 192.168.1.175:10514 10.187.1.3:20001 10.187.1.5:20001
*/
package main
import (
"fmt"
"net"
"os"
"os/signal"
"syscall"
)
var in_count, out_count, err_count uint64
func die(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, "ERROR: " + format + "\n", args...)
os.Exit(1)
}
func put_stats() {
fmt.Fprintf(os.Stdout, " in: %d pkts\n", in_count)
fmt.Fprintf(os.Stdout, "out: %d pkts\n", out_count)
fmt.Fprintf(os.Stdout, "err: %d pkts\n", err_count)
}
func scatter(out []*net.UDPConn) (ref_c chan []byte) {
ref_c = make(chan []byte, 256)
go func() {
for {
pkt := <- ref_c
for _, o := range out {
_, err := o.Write(pkt)
if err != nil {
err_count++
fmt.Fprintf(
os.Stderr,
"Write(%s) failed: %s\n",
o.RemoteAddr().String(),
err,
)
put_stats()
} else {
out_count++
}
}
}
}()
return ref_c
}
func reflect(in *net.UDPConn, out []*net.UDPConn) {
ref_c := scatter(out)
for {
var buf [2048]byte // larger than udp packet
nb, err := in.Read(buf[:])
if err != nil {
die("in.Read(udp4) failed: %s", err)
}
if nb == 0 {
die("in.Read(udp4): zero bytes")
}
ref_c <- buf[:nb]
in_count++
}
}
func main() {
argc := len(os.Args)
if argc < 3 {
die("wrong number of cli args: got %d, expected > 1", argc)
}
// open udp4 listener
addr, err := net.ResolveUDPAddr("udp4", os.Args[1])
if err != nil {
die("net.ResolveUDPAddr(%s) failed: %s", os.Args[1], err)
}
in, err := net.ListenUDP("udp4", addr)
if err != nil {
die("net.ListenUDP(%s) failed: %s", addr, err)
}
// open udp4 "reflectors"
out := make([]*net.UDPConn, argc - 2)
for i := 2; i < argc; i++ {
arg := os.Args[i]
addr, err := net.ResolveUDPAddr("udp4", arg)
if err != nil {
die("net.ResolveUDPAddr(%s) failed: %s", arg, err)
}
conn, err := net.DialUDP("udp4", nil, addr)
if err != nil {
die("net.DialUDP(%s) failed: %s", addr, err)
}
out[i-2] = conn
}
go reflect(in, out)
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM)
for {
sig := <-sigc
if sig != syscall.SIGUSR1 {
fmt.Fprintf(
os.Stderr,
"\nudp4-reflect: %d pkts, caught signal: %s\n",
in_count,
sig,
)
os.Exit(1)
}
put_stats()
}
os.Exit(0)
}