-
Notifications
You must be signed in to change notification settings - Fork 107
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
44e31f4
commit 3988415
Showing
4 changed files
with
216 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"math/rand" | ||
"net" | ||
"os" | ||
"os/exec" | ||
"runtime" | ||
"strconv" | ||
"strings" | ||
"time" | ||
|
||
"github.com/FlowerWrong/netstack/tcpip" | ||
"github.com/FlowerWrong/netstack/tcpip/link/fdbased" | ||
"github.com/FlowerWrong/netstack/tcpip/network/ipv4" | ||
"github.com/FlowerWrong/netstack/tcpip/network/ipv6" | ||
"github.com/FlowerWrong/netstack/tcpip/stack" | ||
"github.com/FlowerWrong/netstack/tcpip/transport/tcp" | ||
"github.com/FlowerWrong/netstack/waiter" | ||
"github.com/FlowerWrong/water" | ||
) | ||
|
||
// sudo go run cmd/netstack/main.go tun2 10.0.0.2 8090 | ||
// telnet 10.0.0.2 8090 | ||
|
||
func echo(wq *waiter.Queue, ep tcpip.Endpoint) { | ||
defer ep.Close() | ||
|
||
// Create wait queue entry that notifies a channel. | ||
waitEntry, notifyCh := waiter.NewChannelEntry(nil) | ||
|
||
wq.EventRegister(&waitEntry, waiter.EventIn) | ||
defer wq.EventUnregister(&waitEntry) | ||
|
||
for { | ||
v, err := ep.Read(nil) | ||
if err != nil { | ||
if err == tcpip.ErrWouldBlock { | ||
<-notifyCh | ||
continue | ||
} | ||
|
||
return | ||
} | ||
|
||
ep.Write(tcpip.SlicePayload(v), tcpip.WriteOptions{}) | ||
} | ||
} | ||
|
||
func execCommand(name, sargs string) error { | ||
args := strings.Split(sargs, " ") | ||
cmd := exec.Command(name, args...) | ||
log.Println("exec command: %s %s", name, sargs) | ||
return cmd.Run() | ||
} | ||
|
||
func addRoute(tun string, subnet *net.IPNet) error { | ||
ip := subnet.IP | ||
maskIP := net.IP(subnet.Mask) | ||
sargs := fmt.Sprintf("-n add -net %s -netmask %s -interface %s", ip.String(), maskIP.String(), tun) | ||
return execCommand("route", sargs) | ||
} | ||
|
||
func main() { | ||
if len(os.Args) != 4 { | ||
log.Fatal("Usage: ", os.Args[0], " <tun-device> <local-address> <local-port>") | ||
} | ||
|
||
// tunName := os.Args[1] | ||
addrName := os.Args[2] | ||
portName := os.Args[3] | ||
|
||
rand.Seed(time.Now().UnixNano()) | ||
|
||
log.SetFlags(log.LstdFlags | log.Lshortfile) | ||
|
||
// Parse the IP address. Support both ipv4 and ipv6. | ||
parsedAddr := net.ParseIP(addrName) | ||
if parsedAddr == nil { | ||
log.Fatalf("Bad IP address: %v", addrName) | ||
} | ||
|
||
var addr tcpip.Address | ||
var proto tcpip.NetworkProtocolNumber | ||
if parsedAddr.To4() != nil { | ||
addr = tcpip.Address(parsedAddr.To4()) | ||
proto = ipv4.ProtocolNumber | ||
} else if parsedAddr.To16() != nil { | ||
addr = tcpip.Address(parsedAddr.To16()) | ||
proto = ipv6.ProtocolNumber | ||
} else { | ||
log.Fatalf("Unknown IP type: %v", addrName) | ||
} | ||
|
||
localPort, err := strconv.Atoi(portName) | ||
if err != nil { | ||
log.Fatalf("Unable to convert port %v: %v", portName, err) | ||
} | ||
|
||
// Create the stack with ip and tcp protocols, then add a tun-based | ||
// NIC and address. | ||
s := stack.New([]string{ipv4.ProtocolName, ipv6.ProtocolName}, []string{tcp.ProtocolName}) | ||
|
||
var mtu uint32 = 1500 | ||
|
||
ifce, err := water.New(water.Config{ | ||
DeviceType: water.TUN, | ||
}) | ||
if err != nil { | ||
log.Fatal("Create tun interface failed", err) | ||
} | ||
log.Println("[tun] interface name is", ifce.Name()) | ||
|
||
if runtime.GOOS == "darwin" { | ||
sargs := fmt.Sprintf("%s 10.0.0.1 10.0.0.2 mtu %d netmask 255.255.255.0 up", ifce.Name(), mtu) | ||
if err := execCommand("/sbin/ifconfig", sargs); err != nil { | ||
log.Println(err) | ||
return | ||
} | ||
} else if runtime.GOOS == "linux" { | ||
sargs := fmt.Sprintf("%s 10.0.0.1 netmask 255.255.255.0", ifce.Name()) | ||
if err := execCommand("/sbin/ifconfig", sargs); err != nil { | ||
log.Println(err) | ||
return | ||
} | ||
} else { | ||
log.Println("not support os") | ||
return | ||
} | ||
|
||
// Parse the mac address. | ||
maddr, err := net.ParseMAC("aa:00:01:01:01:01") | ||
if err != nil { | ||
log.Fatalf("Bad MAC address: aa:00:01:01:01:01") | ||
} | ||
|
||
linkID := fdbased.New(ifce, &fdbased.Options{ | ||
FD: ifce.Fd(), | ||
MTU: 1500, | ||
EthernetHeader: false, | ||
Address: tcpip.LinkAddress(maddr), | ||
}) | ||
|
||
if err := s.CreateNIC(1, linkID, true, addr, uint16(localPort)); err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
if err := s.AddAddress(1, proto, addr); err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
// Add default route. | ||
s.SetRouteTable([]tcpip.Route{ | ||
{ | ||
Destination: tcpip.Address(strings.Repeat("\x00", len(addr))), | ||
Mask: tcpip.Address(strings.Repeat("\x00", len(addr))), | ||
Gateway: "", | ||
NIC: 1, | ||
}, | ||
}) | ||
|
||
// Create TCP endpoint, bind it, then start listening. | ||
var wq waiter.Queue | ||
ep, e := s.NewEndpoint(tcp.ProtocolNumber, proto, &wq) | ||
if err != nil { | ||
log.Fatal(e) | ||
} | ||
|
||
defer ep.Close() | ||
|
||
if err := ep.Bind(tcpip.FullAddress{0, "", uint16(localPort)}, nil); err != nil { | ||
log.Fatal("Bind failed: ", err) | ||
} | ||
|
||
if err := ep.Listen(1024); err != nil { | ||
log.Fatal("Listen failed: ", err) | ||
} | ||
|
||
// Wait for connections to appear. | ||
waitEntry, notifyCh := waiter.NewChannelEntry(nil) | ||
wq.EventRegister(&waitEntry, waiter.EventIn) | ||
defer wq.EventUnregister(&waitEntry) | ||
|
||
for { | ||
n, wq, err := ep.Accept() | ||
if err != nil { | ||
if err == tcpip.ErrWouldBlock { | ||
<-notifyCh | ||
continue | ||
} | ||
|
||
log.Fatal("Accept() failed:", err) | ||
} | ||
|
||
go echo(wq, n) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters