github.com/clmul/water@v0.0.3-0.20221017135504-100d910a03ab/README.md (about) 1 # water 2 3 `water` is a native Go library for [TUN/TAP](http://en.wikipedia.org/wiki/TUN/TAP) interfaces. 4 5 `water` is designed to be simple and efficient. It 6 7 * wraps almost only syscalls and uses only Go standard types; 8 * exposes standard interfaces; plays well with standard packages like `io`, `bufio`, etc.. 9 * does not handle memory management (allocating/destructing slice). It's up to user to decide whether/how to reuse buffers. 10 11 ~~`water/waterutil` has some useful functions to interpret MAC frame headers and IP packet headers. It also contains some constants such as protocol numbers and ethernet frame types.~~ 12 13 See https://github.com/songgao/packets for functions for parsing various packets. 14 15 ## Supported Platforms 16 17 * Linux 18 * Windows (experimental; APIs might change) 19 * macOS (point-to-point TUN only) 20 21 ## Installation 22 ``` 23 go get -u github.com/songgao/water 24 go get -u github.com/songgao/water/waterutil 25 ``` 26 27 ## Documentation 28 [http://godoc.org/github.com/songgao/water](http://godoc.org/github.com/songgao/water) 29 30 ## Example 31 32 ### TAP on Linux: 33 34 ```go 35 package main 36 37 import ( 38 "log" 39 40 "github.com/songgao/packets/ethernet" 41 "github.com/songgao/water" 42 ) 43 44 func main() { 45 config := water.Config{ 46 DeviceType: water.TAP, 47 } 48 config.Name = "O_O" 49 50 ifce, err := water.New(config) 51 if err != nil { 52 log.Fatal(err) 53 } 54 var frame ethernet.Frame 55 56 for { 57 frame.Resize(1500) 58 n, err := ifce.Read([]byte(frame)) 59 if err != nil { 60 log.Fatal(err) 61 } 62 frame = frame[:n] 63 log.Printf("Dst: %s\n", frame.Destination()) 64 log.Printf("Src: %s\n", frame.Source()) 65 log.Printf("Ethertype: % x\n", frame.Ethertype()) 66 log.Printf("Payload: % x\n", frame.Payload()) 67 } 68 } 69 ``` 70 71 This piece of code creates a `TAP` interface, and prints some header information for every frame. After pull up the `main.go`, you'll need to bring up the interface and assign an IP address. All of these need root permission. 72 73 ```bash 74 sudo go run main.go 75 ``` 76 77 In a new terminal: 78 79 ```bash 80 sudo ip addr add 10.1.0.10/24 dev O_O 81 sudo ip link set dev O_O up 82 ``` 83 84 Wait until the output `main.go` terminal, try sending some ICMP broadcast message: 85 ```bash 86 ping -c1 -b 10.1.0.255 87 ``` 88 89 You'll see output containing the IPv4 ICMP frame: 90 ``` 91 2016/10/24 03:18:16 Dst: ff:ff:ff:ff:ff:ff 92 2016/10/24 03:18:16 Src: 72:3c:fc:29:1c:6f 93 2016/10/24 03:18:16 Ethertype: 08 00 94 2016/10/24 03:18:16 Payload: 45 00 00 54 00 00 40 00 40 01 25 9f 0a 01 00 0a 0a 01 00 ff 08 00 01 c1 08 49 00 01 78 7d 0d 58 00 00 00 00 a2 4c 07 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 95 ``` 96 97 ### TUN on macOS 98 99 ```go 100 package main 101 102 import ( 103 "log" 104 105 "github.com/songgao/water" 106 ) 107 108 func main() { 109 ifce, err := water.New(water.Config{ 110 DeviceType: water.TUN, 111 }) 112 if err != nil { 113 log.Fatal(err) 114 } 115 116 log.Printf("Interface Name: %s\n", ifce.Name()) 117 118 packet := make([]byte, 2000) 119 for { 120 n, err := ifce.Read(packet) 121 if err != nil { 122 log.Fatal(err) 123 } 124 log.Printf("Packet Received: % x\n", packet[:n]) 125 } 126 } 127 ``` 128 129 Run it! 130 131 ```bash 132 $ sudo go run main.go 133 ``` 134 135 This is a point-to-point only interface. Use `ifconfig` to see its attributes. You need to bring it up and assign IP addresses (apparently replace `utun2` if needed): 136 137 ```bash 138 $ sudo ifconfig utun2 10.1.0.10 10.1.0.20 up 139 ``` 140 141 Now send some ICMP packets to the interface: 142 143 ```bash 144 $ ping 10.1.0.20 145 ``` 146 147 You'd see the ICMP packets printed out: 148 149 ``` 150 2017/03/20 21:17:30 Interface Name: utun2 151 2017/03/20 21:17:40 Packet Received: 45 00 00 54 e9 1d 00 00 40 01 7d 6c 0a 01 00 0a 0a 01 00 14 08 00 ee 04 21 15 00 00 58 d0 a9 64 00 08 fb a5 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37 152 ``` 153 154 #### Caveats 155 156 1. Only Point-to-Point user TUN devices are supported. TAP devices are *not* supported natively by macOS. 157 2. Custom interface names are not supported by macOS. Interface names are automatically generated serially, using the `utun<#>` naming convention. 158 159 ### TAP on Windows: 160 161 To use it with windows, you will need to install a [tap driver](https://github.com/OpenVPN/tap-windows6), or [OpenVPN client](https://github.com/OpenVPN/openvpn) for windows. 162 163 It's compatible with the Linux code. 164 165 ```go 166 package main 167 168 import ( 169 "log" 170 171 "github.com/songgao/packets/ethernet" 172 "github.com/songgao/water" 173 ) 174 175 func main() { 176 ifce, err := water.New(water.Config{ 177 DeviceType: water.TAP, 178 }) 179 if err != nil { 180 log.Fatal(err) 181 } 182 var frame ethernet.Frame 183 184 for { 185 frame.Resize(1500) 186 n, err := ifce.Read([]byte(frame)) 187 if err != nil { 188 log.Fatal(err) 189 } 190 frame = frame[:n] 191 log.Printf("Dst: %s\n", frame.Destination()) 192 log.Printf("Src: %s\n", frame.Source()) 193 log.Printf("Ethertype: % x\n", frame.Ethertype()) 194 log.Printf("Payload: % x\n", frame.Payload()) 195 } 196 } 197 ``` 198 199 Same as Linux version, but you don't need to bring up the device by hand, the only thing you need is to assign an IP address to it. 200 201 ```dos 202 go run main.go 203 ``` 204 205 It will output a lot of lines because of some windows services and dhcp. 206 You will need admin right to assign IP. 207 208 In a new cmd (admin right): 209 210 ```dos 211 # Replace with your device name, it can be achieved by ifce.Name(). 212 netsh interface ip set address name="Ehternet 2" source=static addr=10.1.0.10 mask=255.255.255.0 gateway=none 213 ``` 214 215 The `main.go` terminal should be silenced after IP assignment, try sending some ICMP broadcast message: 216 217 ```dos 218 ping 10.1.0.255 219 ``` 220 221 You'll see output containing the IPv4 ICMP frame same as the Linux version. 222 223 ## TODO 224 * tuntaposx for TAP on Darwin 225 226 ## Alternatives 227 `tuntap`: [https://code.google.com/p/tuntap/](https://code.google.com/p/tuntap/)