├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── cmd ├── README.md ├── application │ ├── dns │ │ ├── README.md │ │ ├── dns_client.go │ │ └── dns_server.go │ ├── http │ │ ├── httpclient.go │ │ └── httpserver.go │ └── websocket │ │ ├── websocketclient.go │ │ └── websocketserver.go ├── arp.md ├── http.md ├── link │ └── tap │ │ └── main.go ├── network │ ├── arp │ │ └── main.go │ └── ping │ │ └── main.go ├── port │ └── main.go ├── tcp.md ├── transport │ ├── tcp │ │ ├── client.go │ │ ├── client │ │ │ └── main.go │ │ ├── main.go │ │ └── server │ │ │ └── main.go │ └── udp │ │ ├── client │ │ └── main.go │ │ ├── net_client.go │ │ └── server │ │ └── main.go ├── udp.md └── websocket.md ├── config └── net.go ├── go.mod ├── go.sum ├── http-api.md ├── internal ├── endpoint │ └── endpoint.go └── socket │ └── socket.go ├── pkg ├── buffer │ ├── prependable.go │ ├── string.go │ ├── url.go │ ├── view.go │ └── view_test.go ├── checker │ └── checker.go ├── ilist │ └── list.go ├── logging │ └── log.go ├── rand │ └── rand.go ├── reexec │ ├── README.md │ ├── command_linux.go │ ├── command_unix.go │ ├── command_unsupported.go │ ├── command_windows.go │ └── reexec.go ├── seqnum │ └── seqnum.go ├── sleep │ ├── commit_amd64.s │ ├── commit_asm.go │ ├── commit_noasm.go │ ├── empty.s │ ├── sleep_test.go │ └── sleep_unsafe.go ├── syscall │ ├── c_net │ │ ├── net.go │ │ ├── net_test.go │ │ ├── network.c │ │ ├── network.h │ │ ├── nl.c │ │ └── nl.h │ └── pivot_root.go ├── tmutex │ ├── tmutex.go │ └── tmutex_test.go └── waiter │ ├── waiter.go │ └── waiter_test.go ├── protocol ├── application │ ├── dns │ │ ├── endopoint.go │ │ ├── query.go │ │ └── rsp.go │ ├── http │ │ ├── client.go │ │ ├── connection.go │ │ ├── define.go │ │ ├── define_status.go │ │ ├── header.go │ │ ├── interface.go │ │ ├── pkg.go │ │ ├── request.go │ │ ├── request_client.go │ │ ├── response.go │ │ ├── server.go │ │ ├── server_patttern.go │ │ └── server_socket.go │ └── websocket │ │ ├── client.go │ │ ├── conn.go │ │ ├── upgrade.go │ │ └── utils.go ├── header │ ├── arp.go │ ├── checksum.go │ ├── dns.go │ ├── eth.go │ ├── icmpv4.go │ ├── icmpv6.go │ ├── interfaces.go │ ├── ipv4.go │ ├── ipv6.go │ ├── ipv6_fragment.go │ ├── tcp.go │ ├── tcp_test.go │ └── udp.go ├── link │ ├── channel │ │ └── channel.go │ ├── fdbased │ │ └── endpoint.go │ ├── loopback │ │ └── loopback.go │ ├── rawfile │ │ ├── blockingpoll_unsafe.go │ │ ├── errors.go │ │ └── rawfile_unsafe.go │ ├── sniffer │ │ ├── pcap.go │ │ └── sniffer.go │ └── tuntap │ │ └── tuntap.go ├── network │ ├── arp │ │ ├── arp.go │ │ └── arp_test.go │ ├── fragmentation │ │ ├── frag_heap.go │ │ ├── frag_heap_test.go │ │ ├── fragmentation.go │ │ ├── fragmentation_test.go │ │ ├── reassembler.go │ │ ├── reassembler_list.go │ │ └── reassembler_test.go │ ├── hash │ │ └── hash.go │ ├── ip_test.go │ ├── ipv4 │ │ ├── icmp.go │ │ ├── ip.go │ │ ├── ipv4.go │ │ └── ipv4_test.go │ └── ipv6 │ │ ├── icmp.go │ │ ├── icmp_test.go │ │ └── ipv6.go ├── ports │ ├── ports.go │ └── ports_test.go ├── tcpip.go ├── time.s ├── time_unsafe.go └── transport │ ├── ping │ ├── endpoint.go │ ├── ping_packet_list.go │ └── protocol.go │ ├── tcp │ ├── accept.go │ ├── client │ │ ├── client.go │ │ ├── get.go │ │ ├── read.go │ │ └── write.go │ ├── connect.go │ ├── cubic.go │ ├── dual_stack_test.go │ ├── endpoint.go │ ├── forwarder.go │ ├── protocol.go │ ├── rcv.go │ ├── reno.go │ ├── sack.go │ ├── segment.go │ ├── segment_heap.go │ ├── segment_queue.go │ ├── snd.go │ ├── tcp_sack_test.go │ ├── tcp_segment_list.go │ ├── tcp_test.go │ ├── tcp_timestamp_test.go │ ├── testing │ │ └── context │ │ │ └── context.go │ └── timer.go │ ├── tcpconntrack │ ├── tcp_conntrack.go │ └── tcp_conntrack_test.go │ └── udp │ ├── client │ ├── client.go │ ├── get.go │ ├── read.go │ └── write.go │ ├── endpoint.go │ ├── protocol.go │ ├── udp_packet_list.go │ └── udp_test.go ├── resource ├── arp.png ├── dns_client.png ├── dns_server.png ├── e1.png ├── e2.png ├── http.png ├── websocket.png └── wm.png ├── stack ├── linkaddrcache.go ├── linkaddrcache_test.go ├── nic.go ├── registration.go ├── route.go ├── stack.go ├── stack_test.go ├── stackinit │ └── init.go ├── transport_demuxer.go └── transport_test.go ├── tcp-api.md ├── tool ├── Makefile ├── README.md ├── down.go └── up.go ├── udp-api.md └── websocket-api.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM centos:7 2 | 3 | LABEL maintainer="brewlin" version="1.0" license="MIT" 4 | 5 | RUN yum install -y gcc-c++ 6 | 7 | ENV PATH /usr/local/go/bin:$PATH 8 | ENV GOROOT /usr/local/go 9 | ENV GOPATH /home/go 10 | 11 | RUN yum -y install wget \ 12 | && mkdir /home/go \ 13 | && wget https://studygolang.com/dl/golang/go1.13.10.linux-amd64.tar.gz \ 14 | && tar -C /usr/local -zxf go1.13.10.linux-amd64.tar.gz \ 15 | && yum -y install iproute net-tools 16 | 17 | RUN echo export GOROOT=/usr/local/go >> /etc/profile 18 | RUN echo export GOPATH=/home/go >> /etc/profile 19 | RUN echo "export PATH=$PATH:/usr/local/go/bin" >> /etc/profile 20 | RUN rm -f go1.13.10.linux-amd64.tar.gz 21 | RUN source /etc/profile && go version 22 | RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ 23 | && echo 'Asia/Shanghai' >/etc/timezone 24 | 25 | ADD . /test/net-protocol 26 | 27 | RUN cd /test/net-protocol \ 28 | && cd tool \ 29 | && go build -x up.go \ 30 | && ./up 31 | 32 | WORKDIR /test/net-protocol 33 | 34 | CMD [ "/test/net-protocol/tool/up"] -------------------------------------------------------------------------------- /cmd/application/dns/README.md: -------------------------------------------------------------------------------- 1 | [toc] 2 | # DNS ClIENT 3 | ``` 4 | > cd net-protocol/tool; 5 | > go build up.go 6 | > sudo ./up 7 | 8 | > cd net-protocol/cmd/application/dns 9 | > sudo go run dns_client.go 10 | ``` 11 | ![](../../../resource/dns_client.png) 12 | 13 | 14 | # DNS SERVER 15 | 启动 udp server,另起窗口发送dns查询并指定dnsserver 16 | ``` 17 | > cd net-protocol/tool; 18 | > go build up.go 19 | > sudo ./up 20 | 21 | > cd net-protocol/cmd/application/dns 22 | > sudo go run dns_server.go 23 | //另起ssh窗口 发送dns查询并指定自定义的dns server 192.168.1.1:53 24 | > nslookup www.baidu.com 192.168.1.1 25 | ``` 26 | ![](../../../resource/dns_server.png) -------------------------------------------------------------------------------- /cmd/application/dns/dns_client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/brewlin/net-protocol/protocol/application/dns" 6 | "github.com/brewlin/net-protocol/protocol/header" 7 | ) 8 | 9 | func main() { 10 | d := dns.NewEndpoint("www.baidu.com") 11 | fmt.Println("DNS lookuphost : www.baidu.com") 12 | defer d.Close() 13 | 14 | ir,err := d.Resolve(); 15 | if err != nil { 16 | fmt.Println(err) 17 | return 18 | } 19 | for _,v := range *ir { 20 | switch v.Type { 21 | case header.A: 22 | fmt.Println("A(host name) :",v.Address) 23 | case header.CNAME: 24 | fmt.Println("CNAME (alias name):",v.Address) 25 | } 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /cmd/application/dns/dns_server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/brewlin/net-protocol/config" 6 | "github.com/brewlin/net-protocol/internal/endpoint" 7 | "github.com/brewlin/net-protocol/pkg/buffer" 8 | _ "github.com/brewlin/net-protocol/pkg/logging" 9 | _ "github.com/brewlin/net-protocol/pkg/logging" 10 | "github.com/brewlin/net-protocol/pkg/waiter" 11 | "github.com/brewlin/net-protocol/protocol/header" 12 | "github.com/brewlin/net-protocol/protocol/network/ipv4" 13 | "github.com/brewlin/net-protocol/protocol/transport/udp" 14 | "github.com/brewlin/net-protocol/protocol/transport/udp/client" 15 | "github.com/brewlin/net-protocol/stack" 16 | "log" 17 | "strconv" 18 | "strings" 19 | 20 | tcpip "github.com/brewlin/net-protocol/protocol" 21 | ) 22 | 23 | //当前demo作为一个dns代理,接受dns请求并转发后,解析响应做一些操作 24 | func main() { 25 | s := endpoint.NewEndpoint() 26 | 27 | udploop(s) 28 | 29 | } 30 | func udploop(s *stack.Stack) { 31 | var wq waiter.Queue 32 | //新建一个UDP端 33 | ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 34 | if err != nil { 35 | log.Fatal(err) 36 | } 37 | //绑定本地端口 53是dns默认端口 38 | if err := ep.Bind(tcpip.FullAddress{1, config.LocalAddres, 53}, nil); err != nil { 39 | log.Fatal("@main : bind failed :", err) 40 | } 41 | defer ep.Close() 42 | //创建队列 通知 channel 43 | waitEntry, notifych := waiter.NewChannelEntry(nil) 44 | wq.EventRegister(&waitEntry, waiter.EventIn) 45 | defer wq.EventUnregister(&waitEntry) 46 | 47 | var saddr tcpip.FullAddress 48 | 49 | for { 50 | v, _, err := ep.Read(&saddr) 51 | if err != nil { 52 | if err == tcpip.ErrWouldBlock { 53 | <-notifych 54 | continue 55 | } 56 | fmt.Println(err) 57 | return 58 | } 59 | //接收到代理请求 60 | h := header.DNS(v) 61 | fmt.Println("@main :接收到代理域名:", string(h[header.DOMAIN:header.DOMAIN+h.GetDomainLen()-1])) 62 | go handle_proxy(v,ep,saddr) 63 | } 64 | } 65 | //转发代理请求,并解析响应数据 66 | func handle_proxy(v buffer.View,ep tcpip.Endpoint,saddr tcpip.FullAddress){ 67 | cli := client.NewClient("8.8.8.8",53) 68 | cli.Connect() 69 | cli.Write(v) 70 | defer cli.Close() 71 | 72 | rsp,err := cli.Read() 73 | if err != nil { 74 | fmt.Println(err) 75 | return 76 | } 77 | //返回给客户端 78 | _, _, err = ep.Write(tcpip.SlicePayload(rsp), tcpip.WriteOptions{To: &saddr}) 79 | if err != nil { 80 | fmt.Println(err) 81 | } 82 | p := header.DNS(rsp) 83 | answer := p.GetAnswer() 84 | 85 | for i := 0; i < len(*answer) ; i++ { 86 | switch (*answer)[i].Type { 87 | case header.A: 88 | fmt.Println("dns 目标IP(A):",parseAName((*answer)[i].RData)) 89 | case header.CNAME: 90 | fmt.Println("dns 目标IP(alias):",parseCName((*answer)[i].RData)) 91 | } 92 | } 93 | } 94 | func parseAName(rd []byte) string { 95 | res := []string{} 96 | for _,v := range rd { 97 | res = append(res,strconv.Itoa(int(v))) 98 | } 99 | return strings.Join(res,".") 100 | } 101 | 102 | func parseCName(rd []byte) (res string) { 103 | for{ 104 | l := int(rd[0]) 105 | if l >= len(rd){ 106 | res += ".com" 107 | return 108 | } 109 | rd = rd[1:] 110 | res += string(rd[0:l]) 111 | rd = rd[l:] 112 | if len(rd) == 0 { 113 | return 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /cmd/application/http/httpclient.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/brewlin/net-protocol/pkg/logging" 6 | "github.com/brewlin/net-protocol/protocol/application/http" 7 | ) 8 | 9 | func init() { 10 | logging.Setup() 11 | 12 | } 13 | func main(){ 14 | cli,err := http.NewClient("http://10.0.2.15:8080/test") 15 | if err != nil { 16 | panic(err) 17 | return 18 | } 19 | cli.SetMethod("GET") 20 | cli.SetData("test") 21 | res,err := cli.GetResult() 22 | fmt.Println(res) 23 | 24 | } -------------------------------------------------------------------------------- /cmd/application/http/httpserver.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/brewlin/net-protocol/config" 6 | 7 | "github.com/brewlin/net-protocol/pkg/logging" 8 | "github.com/brewlin/net-protocol/protocol/application/http" 9 | ) 10 | 11 | func init() { 12 | logging.Setup() 13 | } 14 | func main() { 15 | serv := http.NewHTTP(config.NicName, "192.168.1.0/24", "192.168.1.1", "9502") 16 | serv.HandleFunc("/", func(request *http.Request, response *http.Response) { 17 | fmt.Println("hell0 ----------------------") 18 | response.End("hello") 19 | }) 20 | serv.ListenAndServ() 21 | } 22 | -------------------------------------------------------------------------------- /cmd/application/websocket/websocketclient.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/brewlin/net-protocol/pkg/logging" 6 | "github.com/brewlin/net-protocol/protocol/application/websocket" 7 | ) 8 | 9 | func init() { 10 | logging.Setup() 11 | 12 | } 13 | func main(){ 14 | wscli ,_ := websocket.NewClient("http://10.0.2.15:8080/ws") 15 | defer wscli.Close() 16 | //升级 http协议为websocket 17 | if err := wscli.Upgrade();err != nil { 18 | panic(err) 19 | } 20 | //循环接受数据 21 | for { 22 | if err := wscli.Push("test");err != nil { 23 | break 24 | } 25 | data,_ := wscli.Recv() 26 | fmt.Println(data) 27 | } 28 | } -------------------------------------------------------------------------------- /cmd/application/websocket/websocketserver.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/brewlin/net-protocol/config" 6 | "log" 7 | 8 | "github.com/brewlin/net-protocol/pkg/logging" 9 | "github.com/brewlin/net-protocol/protocol/application/http" 10 | "github.com/brewlin/net-protocol/protocol/application/websocket" 11 | ) 12 | 13 | func init() { 14 | logging.Setup() 15 | } 16 | func main() { 17 | serv := http.NewHTTP(config.NicName, "192.168.1.0/24", "192.168.1.1", "9502") 18 | serv.HandleFunc("/ws", echo) 19 | 20 | serv.HandleFunc("/", func(request *http.Request, response *http.Response) { 21 | response.End("hello") 22 | }) 23 | fmt.Println("@main: server is start ip:192.168.1.1 port:9502 ") 24 | serv.ListenAndServ() 25 | } 26 | 27 | //websocket处理器 28 | func echo(r *http.Request, w *http.Response) { 29 | fmt.Println("got http request ; start to upgrade websocket protocol....") 30 | //协议升级 c *websocket.Conn 31 | c, err := websocket.Upgrade(r, w) 32 | if err != nil { 33 | //升级协议失败,直接return 交由http处理响应 34 | fmt.Println("Upgrade error:", err) 35 | return 36 | } 37 | defer c.Close() 38 | //循环处理数据,接受数据,然后返回 39 | for { 40 | message, err := c.ReadData() 41 | if err != nil { 42 | log.Println("read:", err) 43 | break 44 | } 45 | fmt.Println("recv client msg:", string(message)) 46 | // c.SendData(message ) 47 | c.SendData([]byte("hello")) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /cmd/arp.md: -------------------------------------------------------------------------------- 1 | # arp协议 2 | arp协议主要用户获取ip对应的mac物理地址,主机和主机间通信是基于mac物理地址通信的,所有arp协议正为此而生, 3 | 4 | arp有一个本地的arp缓存表,用来缓存本地arp映射关系,加快网络请求,不必在通信的时候每次去广播查询mac地址 5 | ## arp 6 | ![arp](../resource/arp.png) 7 | 硬件类型(hard type) 硬件类型用来指代需要什么样的物理地址,如果硬件类型为 1,表示以太网地址 8 | 9 | 协议类型 协议类型则是需要映射的协议地址类型,如果协议类型是 0x0806,表示 arp 协议。 10 | 11 | 硬件地址长度 表示硬件地址的长度,单位字节,一般都是以太网地址的长度为 6 字节。 12 | 13 | 协议地址长度: 14 | 表示协议地址的长度,单位字节,一般都是 ipv4 地址的长度为 4 字节。 15 | 16 | 操作码 这些值用于区分具体操作类型,因为字段都相同,所以必须指明操作码,不然连请求还是应答都分不清。 17 | 1=>ARP 请求, 2=>ARP 应答,3=>RARP 请求,4=>RARP 应答。 18 | 19 | 源硬件地址 源物理地址,如02:f2:02:f2:02:f2 20 | 21 | 源协议地址 源协议地址,如192.168.0.1 22 | 23 | 目标硬件地址 目标物理地址,如03:f2:03:f2:03:f2 24 | 25 | 目标协议地址。 目标协议地址,如192.168.0.2 26 | ## arp 测试 27 | 启动网卡 注册相关协议 ip协议 arp协议 以太网协议,icmq协议等,接受网卡原始数据 28 | ``` 29 | cd arp; 30 | go build 31 | sudo ./arp tap1 192.168.1.1/24 32 | 33 | 34 | registration.go:364: @协议栈 stack: register 注册链路层设备LinkEndpointID: 1 35 | stack.go:506: @网卡 stack: 新建网卡对象,并启动网卡事件 36 | nic.go:225: @网卡 nic: 在nic网卡上添加网络层,注册和初始化网络协议 protocol: 2048 addr: 192.168.1.1 peb: 0 37 | nic.go:225: @网卡 nic: 在nic网卡上添加网络层,注册和初始化网络协议 protocol: 2054 addr: 617270 peb: 0 38 | endpoint.go:190: @链路层 fdbased: dispatch 调度进行事件循环接受物理网卡数据 dispatchLoop 39 | 40 | 41 | endpoint.go:208: @链路层 fdbased: step1 物理网卡接受数据read 42 bytes 42 | endpoint.go:226: @链路层 fdbased: step2 解析以太网协议: [255 255 255 255 255 255 102 226 79 243 181 144 8 6 0 1 8 0 6 4 0 1 102 226 79 243 181 144 10 105 121 88 0 0 0 0 0 0 192 168 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 2054 66:e2:4f:f3:b5:90 ff:ff:ff:ff:ff:ff 43 | nic.go:432: @网卡 nic: step3 nic网卡解析以太网协议,分发到对应的 网络层 协议处理 44 | arp.go:92: @网络层 arp: step1 : 解析arp数据包,包括arp请求和响应 45 | arp.go:103: @网络层 arp: step2 : 解析arp请求 46 | stack.go:777: @网卡 stack: 协议解析 nicid: 1 protocol: 2048 addr: 192.168.1.1 47 | arp.go:115: @网络层 arp: reply: 发送arp回复 48 | endpoint.go:116: @链路层: fdbased 写入网卡数据 0x4bfa10 49 | linkaddrcache.go:152: @路由表 route: linkaddrcache 路由表缓存 1:10.105.121.88:0-66:e2:4f:f3:b5:90 50 | endpoint.go:208: @链路层 fdbased: step1 物理网卡接受数据read 98 bytes 51 | endpoint.go:226: @链路层 fdbased: step2 解析以太网协议: [102 226 79 243 181 144 102 226 79 243 181 144 8 0 69 0 0 84 177 10 64 0 64 1 68 52 10 105 121 88 192 168 1 1 8 0 198 16 8 142 0 1 228 111 111 93 0 0 0 0 19 192 3 0 0 0 0 0 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 2048 66:e2:4f:f3:b5:90 66:e2:4f:f3:b5:90 52 | nic.go:432: @网卡 nic: step3 nic网卡解析以太网协议,分发到对应的 网络层 协议处理 53 | ipv4.go:159: @网络层 ipv4: handlePacket 数据包处理 54 | icmp.go:76: @网络层 icmp: 接受报文:echo 55 | icmp.go:132: @网络层 icmp: 响应报文:传递给ip层处理 56 | ipv4.go:151: @网络层 ipv4: 接受传输层数据 封装ip头部信息,写入链路层网卡数据 send ipv4 packet 84 bytes, proto: 0x1 57 | endpoint.go:116: @链路层: fdbased 写入网卡数据 0x4bfa10 58 | 59 | 60 | 61 | ``` 62 | 发送ping包,arp查询等 63 | ``` 64 | ping 192.168.1.1 65 | 66 | PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data. 67 | 64 bytes from 192.168.1.1: icmp_seq=1 ttl=255 time=1.16 ms 68 | 69 | ``` 70 | 71 | -------------------------------------------------------------------------------- /cmd/http.md: -------------------------------------------------------------------------------- 1 | # http协议 2 | ## start 3 | ``` 4 | cd application/http 5 | go build 6 | sudo ./http 7 | 8 | curl 192.168.1.1:8888/test 9 | ``` 10 | ## @httpserver.go 11 | ``` 12 | import ( 13 | "fmt" 14 | 15 | "github.com/brewlin/net-protocol/pkg/logging" 16 | "github.com/brewlin/net-protocol/protocol/application/http" 17 | ) 18 | 19 | func init() { 20 | logging.Setup() 21 | } 22 | func main() { 23 | serv := http.NewHTTP("tap1", "192.168.1.0/24", "192.168.1.1", "9502") 24 | serv.HandleFunc("/", func(request *http.Request, response *http.Response) { 25 | fmt.Println("hell0 ----------------------") 26 | response.End("hello") 27 | }) 28 | serv.ListenAndServ() 29 | } 30 | ``` 31 | ## 浏览器console 32 | ![](/resource/http.png) 33 | ## @终端log 34 | ``` 35 | @application http: now waiting to new client connection ... 36 | @application http: dispatch got new request 37 | @应用层 http: waiting new event trigger ... 38 | http协议原始数据: 39 | GET /test HTTP/1.1 40 | Host: 192.168.1.1:8888 41 | User-Agent: curl/7.47.0 42 | Accept: */* 43 | 44 | 45 | @application http: header parse method_raw: GET 46 | @application http: header parse method: 1 47 | @application http: header parse uri: /test 48 | @application http: header parse version_raw: HTTP/1.1 49 | @application http: header parse version: 3 50 | @application http: header parse status_code: 0 51 | @application http:response send 构建http响应包体 52 | HTTP/1.1 200 ok 53 | Server: github.com/brewlin/net-protocol/1.00 54 | Connection: close 55 | 56 | SUCCESS

github.com/brewlin/net-protocol/http

57 | @application http: dispatch close this request 58 | 59 | ``` -------------------------------------------------------------------------------- /cmd/link/tap/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "log" 6 | "os" 7 | 8 | "github.com/brewlin/net-protocol/protocol/link/rawfile" 9 | "github.com/brewlin/net-protocol/protocol/link/tuntap" 10 | ) 11 | 12 | func main() { 13 | flag.Parse() 14 | log.SetFlags(log.Lshortfile) 15 | if len(flag.Args()) < 2 { 16 | log.Fatal("Usage: ", os.Args[0], " port") 31 | } 32 | 33 | log.SetFlags(log.Lshortfile | log.LstdFlags) 34 | tapName := flag.Arg(0) 35 | listenAddr := flag.Arg(1) 36 | portName := flag.Arg(2) 37 | 38 | log.Printf("tap: %v,listenAddr:%v,portName:%v", tapName, listenAddr, portName) 39 | 40 | //解析mac地址 41 | maddr, err := net.ParseMAC(*mac) 42 | if err != nil { 43 | log.Fatalf("Bad mac address:%v", *mac) 44 | } 45 | parseAddr := net.ParseIP(listenAddr) 46 | 47 | //解析ip地址,ipv4 或者ipv6 48 | var addr tcpip.Address 49 | var proto tcpip.NetworkProtocolNumber 50 | if parseAddr.To4() != nil { 51 | addr = tcpip.Address(parseAddr.To4()) 52 | proto = ipv4.ProtocolNumber 53 | } else if parseAddr.To16() != nil { 54 | addr = tcpip.Address(parseAddr.To16()) 55 | proto = ipv6.ProtocolNumber 56 | } else { 57 | log.Fatalf("Unknow IP type:%v", parseAddr) 58 | } 59 | 60 | localPort, err := strconv.Atoi(portName) 61 | if err != nil { 62 | log.Fatalf("unable to convert port %v:%v", portName, err) 63 | } 64 | 65 | //虚拟网卡配置 66 | conf := &tuntap.Config{ 67 | Name: tapName, 68 | Mode: tuntap.TAP, 69 | } 70 | 71 | var fd int 72 | //新建虚拟网卡 73 | fd, err = tuntap.NewNetDev(conf) 74 | if err != nil { 75 | log.Fatal(err) 76 | } 77 | //启动tap网卡 78 | tuntap.SetLinkUp(tapName) 79 | //设置tap网卡ip地址 80 | tuntap.AddIP(tapName, listenAddr) 81 | 82 | //抽象网卡的文件接口 实现的接口 83 | linkID := fdbased.New(&fdbased.Options{ 84 | FD: fd, 85 | MTU: 1500, 86 | Address: tcpip.LinkAddress(maddr), 87 | }) 88 | //新建相关协议的协议栈 89 | s := stack.New([]string{ipv4.ProtocolName, arp.ProtocolName}, []string{tcp.ProtocolName, udp.ProtocolName}, stack.Options{}) 90 | 91 | //新建抽象网卡 92 | if err := s.CreateNamedNIC(1, "vnic1", linkID); err != nil { 93 | log.Fatal(err) 94 | } 95 | 96 | //在该协议栈上添加和注册相关的网络层协议 97 | if err := s.AddAddress(1, proto, addr); err != nil { 98 | log.Fatal(err) 99 | } 100 | 101 | //在该协议栈上添加和注册arp协议 102 | if err := s.AddAddress(1, arp.ProtocolNumber, arp.ProtocolAddress); err != nil { 103 | log.Fatal(err) 104 | } 105 | 106 | //添加默认路由 107 | s.SetRouteTable([]tcpip.Route{ 108 | { 109 | Destination: tcpip.Address(strings.Repeat("\x00", len(addr))), 110 | Mask: tcpip.AddressMask(strings.Repeat("\x00", len(addr))), 111 | Gateway: "", 112 | NIC: 1, 113 | }, 114 | }) 115 | //同时监听tcp和udp localPort端口 116 | tcpEp := tcpListen(s, proto, localPort) 117 | udpEp := udpListen(s, proto, localPort) 118 | 119 | //关闭监听服务,释放端口 120 | tcpEp.Close() 121 | udpEp.Close() 122 | } 123 | func tcpListen(s *stack.Stack, proto tcpip.NetworkProtocolNumber, localPort int) tcpip.Endpoint { 124 | var wq waiter.Queue 125 | //新建一个tcp端 126 | ep, err := s.NewEndpoint(tcp.ProtocolNumber, proto, &wq) 127 | if err != nil { 128 | log.Fatal(err) 129 | } 130 | //绑定ip和端口,这里的ip地址为空,表示绑定任何ip 131 | //此时就会调用端口管理器 132 | if err := ep.Bind(tcpip.FullAddress{0, "", uint16(localPort)}, nil); err != nil { 133 | log.Fatal("Bind failed: ", err) 134 | } 135 | //开始监听 136 | if err := ep.Listen(10); err != nil { 137 | log.Fatal("Listen failed : ", err) 138 | } 139 | return ep 140 | } 141 | 142 | func udpListen(s *stack.Stack, proto tcpip.NetworkProtocolNumber, localPort int) tcpip.Endpoint { 143 | var wq waiter.Queue 144 | //新建一个udp端 145 | ep, err := s.NewEndpoint(udp.ProtocolNumber, proto, &wq) 146 | if err != nil { 147 | log.Fatal(err) 148 | } 149 | //绑定ip和端口,这里的ip地址为空,表示绑定任何ip 150 | //此时就会调用端口管理器 151 | if err := ep.Bind(tcpip.FullAddress{0, "", uint16(localPort)}, nil); err != nil { 152 | log.Fatal("Bind failed: ", err) 153 | } 154 | //注意udp是无连接的,它不需要listen 155 | return ep 156 | } 157 | -------------------------------------------------------------------------------- /cmd/tcp.md: -------------------------------------------------------------------------------- 1 | ## tcp 协议实验 2 | ### 新建网卡、启动网卡、添加协议 3 | ```go 4 | func main() { 5 | flag.Parse() 6 | if len(flag.Args()) != 4 { 7 | log.Fatal("usage:", os.Args[0], " ") 8 | } 9 | tapName := flag.Arg(0) 10 | cidrName := flag.Arg(1) 11 | addrName := flag.Arg(2) 12 | portName := flag.Arg(3) 13 | log.Printf("tap :%v addr :%v port :%v", tapName, addrName, portName) 14 | 15 | //解析mac地址 16 | maddr, err := net.ParseMAC(*mac) 17 | if err != nil { 18 | log.Fatal(*mac) 19 | } 20 | parseAddr := net.ParseIP(addrName) 21 | if err != nil { 22 | log.Fatal("BAD ADDRESS", addrName) 23 | } 24 | //解析IP地址,ipv4,或者ipv6 25 | var addr tcpip.Address 26 | var proto tcpip.NetworkProtocolNumber 27 | if parseAddr.To4() != nil { 28 | addr = tcpip.Address(net.ParseIP(addrName).To4()) 29 | proto = ipv4.ProtocolNumber 30 | } else if parseAddr.To16() != nil { 31 | addr = tcpip.Address(net.ParseIP(addrName).To16()) 32 | proto = ipv6.ProtocolNumber 33 | } else { 34 | log.Fatal("unkonw iptype") 35 | } 36 | localPort, err := strconv.Atoi(portName) 37 | if err != nil { 38 | log.Fatalf("unable to convert port") 39 | } 40 | 41 | //虚拟网卡配置 42 | conf := &tuntap.Config{ 43 | Name: tapName, 44 | Mode: tuntap.TAP, 45 | } 46 | 47 | var fd int 48 | //新建虚拟网卡 49 | fd, err = tuntap.NewNetDev(conf) 50 | if err != nil { 51 | log.Fatal(err) 52 | } 53 | //启动网卡 54 | tuntap.SetLinkUp(tapName) 55 | //设置路由 56 | tuntap.SetRoute(tapName, cidrName) 57 | 58 | //抽象网卡层接口 59 | linkID := fdbased.New(&fdbased.Options{ 60 | FD: fd, 61 | MTU: 1500, 62 | Address: tcpip.LinkAddress(maddr), 63 | ResolutionRequired: true, 64 | }) 65 | //新建相关协议的协议栈 66 | s := stack.New([]string{ipv4.ProtocolName, arp.ProtocolName}, []string{tcp.ProtocolName, udp.ProtocolName}, stack.Options{}) 67 | //新建抽象网卡 68 | if err := s.CreateNamedNIC(1, "vnic1", linkID); err != nil { 69 | log.Fatal(err) 70 | } 71 | 72 | //在该协议栈上添加和注册相关的网络层协议 73 | if err := s.AddAddress(1, proto, addr); err != nil { 74 | log.Fatal(err) 75 | } 76 | 77 | //在该协议栈上添加和注册arp协议 78 | if err := s.AddAddress(1, arp.ProtocolNumber, arp.ProtocolAddress); err != nil { 79 | log.Fatal(err) 80 | } 81 | //添加默认路由 82 | s.SetRouteTable([]tcpip.Route{ 83 | { 84 | Destination: tcpip.Address(strings.Repeat("\x00", len(addr))), 85 | Mask: tcpip.AddressMask(strings.Repeat("\x00", len(addr))), 86 | Gateway: "", 87 | NIC: 1, 88 | }, 89 | }) 90 | 91 | tcpServer(s, addr, localPort) 92 | 93 | } 94 | ``` 95 | 96 | ### 监听tcp端口,事件循环接收链接 97 | ```go 98 | func tcpServer(s *stack.Stack, addr tcpip.Address, port int) { 99 | var wq waiter.Queue 100 | //新建一个tcp端 101 | ep, e := s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 102 | if e != nil { 103 | log.Fatal(e) 104 | } 105 | //绑定本地端口 106 | if err := ep.Bind(tcpip.FullAddress{0, "", uint16(port)}, nil); err != nil { 107 | log.Fatal("@main :Bind failed: ", err) 108 | } 109 | //监听tcp 110 | if err := ep.Listen(10); err != nil { 111 | log.Fatal("@main :Listen failed: ", err) 112 | } 113 | //等待连接 出现 114 | waitEntry, notifyCh := waiter.NewChannelEntry(nil) 115 | wq.EventRegister(&waitEntry, waiter.EventIn) 116 | defer wq.EventUnregister(&waitEntry) 117 | 118 | for { 119 | n, q, err := ep.Accept() 120 | if err != nil { 121 | if err == tcpip.ErrWouldBlock { 122 | fmt.Println("@main server:", " now waiting to new client connection ...") 123 | <-notifyCh 124 | continue 125 | } 126 | fmt.Println("@main server: Accept() failed: ", err) 127 | panic(err) 128 | } 129 | addr, _ := n.GetRemoteAddress() 130 | fmt.Println("@main server: new client connection : ", addr) 131 | 132 | go dispatch(n, q, addr) 133 | } 134 | } 135 | ``` 136 | 137 | ### 为每一个tcp连接 分发一个协程处理 138 | ```go 139 | func dispatch(e tcpip.Endpoint, wq *waiter.Queue, addr tcpip.FullAddress) { 140 | //新建队列和通知,因为底层每一次新的连接accept到来,会重新分配 tcpip.Endpoint,然后需要重新初始化当前连接 141 | waitEntry, notifyCh := waiter.NewChannelEntry(nil) 142 | //注册事件 143 | wq.EventRegister(&waitEntry, waiter.EventIn) 144 | 145 | defer wq.EventUnregister(&waitEntry) 146 | defer e.Close() 147 | for { 148 | //读取数据 149 | v, c, err := e.Read(&addr) 150 | if err != nil { 151 | if err == tcpip.ErrWouldBlock { 152 | //表示队列里没有数据可以读取, 153 | fmt.Println("@main dispatch: waiting new event trigger ...") 154 | //阻塞等待通知 155 | <-notifyCh 156 | //表示有事件触发了, 取决于上面 wq.EventRegister(&waitEntry,waiter.EventIn) 157 | continue 158 | } 159 | fmt.Println("@main dispatch:tcp read got error", err) 160 | break 161 | } 162 | fmt.Println("@main dispatch: recv ", v, c) 163 | a, b, er := e.Write(tcpip.SlicePayload(v), tcpip.WriteOptions{To: &addr}) 164 | fmt.Println("@main dispatch: write to client res: ", a, b, er) 165 | } 166 | } 167 | 168 | ``` -------------------------------------------------------------------------------- /cmd/transport/tcp/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/ioutil" 5 | "log" 6 | "net" 7 | "strconv" 8 | 9 | "github.com/brewlin/net-protocol/config" 10 | ) 11 | 12 | func main() { 13 | addr := config.LocalAddres.To4().String() + ":" + strconv.Itoa(int(config.LocalPort)) 14 | tcpaddr, err := net.ResolveTCPAddr("", addr) 15 | if err != nil { 16 | log.Fatal("net Resolvetcp addr error!", err.Error()) 17 | } 18 | log.Println("str tcpaddr = ", tcpaddr.String()) 19 | log.Println("str network = ", tcpaddr.Network()) 20 | 21 | conn, err := net.DialTCP("tcp4", nil, tcpaddr) 22 | log.Println("dial over") 23 | if err != nil { 24 | log.Fatal("net diatcp error!", err.Error()) 25 | } 26 | defer conn.Close() 27 | 28 | blen, err := conn.Write([]byte("HEAD / HTTP/1.0 \r\n\r\n")) 29 | if err != nil { 30 | log.Fatal("err = ", err.Error()) 31 | } 32 | log.Println("blen = ", blen) 33 | res, err := ioutil.ReadAll(conn) 34 | if err != nil { 35 | log.Fatal(err.Error()) 36 | } 37 | log.Println("res = ", string(res)) 38 | log.Println(conn.LocalAddr()) 39 | log.Println(conn.RemoteAddr()) 40 | 41 | } 42 | -------------------------------------------------------------------------------- /cmd/transport/tcp/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/brewlin/net-protocol/pkg/logging" 7 | "github.com/brewlin/net-protocol/protocol/transport/tcp/client" 8 | _ "github.com/brewlin/net-protocol/stack/stackinit" 9 | ) 10 | 11 | func init() { 12 | logging.Setup() 13 | } 14 | func main() { 15 | con := client.NewClient("10.0.2.15", 8080) 16 | if err := con.Connect(); err != nil { 17 | fmt.Println(err) 18 | } 19 | con.Write([]byte("send msg")) 20 | res, _ := con.Read() 21 | // var p [8]byte 22 | // res, _ := con.Readn(p[:1]) 23 | // fmt.Println(p) 24 | fmt.Println("res") 25 | fmt.Println(string(res)) 26 | } 27 | -------------------------------------------------------------------------------- /cmd/transport/tcp/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "log" 6 | "net" 7 | "os" 8 | "strconv" 9 | "strings" 10 | "time" 11 | 12 | "github.com/brewlin/net-protocol/protocol/link/loopback" 13 | 14 | "github.com/brewlin/net-protocol/pkg/waiter" 15 | 16 | "github.com/brewlin/net-protocol/protocol/network/arp" 17 | "github.com/brewlin/net-protocol/protocol/network/ipv4" 18 | "github.com/brewlin/net-protocol/protocol/transport/tcp" 19 | "github.com/brewlin/net-protocol/stack" 20 | 21 | tcpip "github.com/brewlin/net-protocol/protocol" 22 | ) 23 | 24 | var mac = flag.String("mac", "aa:00:01:01:01:01", "mac address to use in tap device") 25 | 26 | func main() { 27 | flag.Parse() 28 | log.SetFlags(log.Lshortfile) 29 | 30 | if len(os.Args) != 3 { 31 | log.Fatal("usage:", os.Args[0], "") 32 | } 33 | addrName := os.Args[1] 34 | portName := os.Args[2] 35 | 36 | addr := tcpip.Address(net.ParseIP(addrName).To4()) 37 | port, err := strconv.Atoi(portName) 38 | if err != nil { 39 | log.Fatal("@main cmd/tcp:Unable to convert port %v:%v", portName, err) 40 | } 41 | s := newStack(addr, port) 42 | done := make(chan int, 1) 43 | go tcpServer(s, addr, port, done) 44 | <-done 45 | tcpClient(s, addr, port) 46 | 47 | } 48 | func newStack(addr tcpip.Address, port int) *stack.Stack { 49 | //创建本地环回网卡 50 | linkID := loopback.New() 51 | //新建相关协议的协议栈 52 | s := stack.New([]string{ipv4.ProtocolName, arp.ProtocolName}, []string{tcp.ProtocolName}, stack.Options{}) 53 | //新建抽象的网卡 54 | if err := s.CreateNamedNIC(1, "lo0", linkID); err != nil { 55 | log.Fatal(err) 56 | } 57 | //在该网卡上添加和注册相应的网络层 58 | if err := s.AddAddress(1, ipv4.ProtocolNumber, addr); err != nil { 59 | log.Fatal(err) 60 | } 61 | //在该协议栈上添加和注册ARP协议 62 | if err := s.AddAddress(1, arp.ProtocolNumber, arp.ProtocolAddress); err != nil { 63 | log.Fatal(err) 64 | } 65 | //添加默认路由 66 | s.SetRouteTable([]tcpip.Route{ 67 | { 68 | Destination: tcpip.Address(strings.Repeat("\x00", len(addr))), 69 | Mask: tcpip.AddressMask(strings.Repeat("\x00", len(addr))), 70 | Gateway: "", 71 | NIC: 1, 72 | }, 73 | }) 74 | return s 75 | } 76 | func tcpServer(s *stack.Stack, addr tcpip.Address, port int, done chan int) { 77 | var wq waiter.Queue 78 | //新建一个tcp端 79 | ep, e := s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 80 | if e != nil { 81 | log.Fatal(e) 82 | } 83 | //绑定本地端口 84 | if err := ep.Bind(tcpip.FullAddress{0, "", uint16(port)}, nil); err != nil { 85 | log.Fatal("@main cmd/tcp: Bind failed: ", err) 86 | } 87 | //监听tcp 88 | if err := ep.Listen(10); err != nil { 89 | log.Fatal("@main cmd/tcp: Listen failed: ", err) 90 | } 91 | //等待连接 出现 92 | waitEntry, notifyCh := waiter.NewChannelEntry(nil) 93 | wq.EventRegister(&waitEntry, waiter.EventIn) 94 | defer wq.EventUnregister(&waitEntry) 95 | 96 | done <- 1 97 | 98 | for { 99 | n, _, err := ep.Accept() 100 | if err != nil { 101 | if err == tcpip.ErrWouldBlock { 102 | <-notifyCh 103 | continue 104 | } 105 | log.Fatal("@main cmd/tcp: Accept() failed: ", err) 106 | } 107 | ra, err := n.GetRemoteAddress() 108 | log.Printf("@main cmd/tcp : new conn: %v %v", ra, err) 109 | } 110 | } 111 | 112 | func tcpClient(s *stack.Stack, addr tcpip.Address, port int) { 113 | remote := tcpip.FullAddress{ 114 | Addr: addr, 115 | Port: uint16(port), 116 | } 117 | var wq waiter.Queue 118 | //新建一个tcp端 119 | ep, e := s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 120 | if e != nil { 121 | log.Fatal(e) 122 | } 123 | 124 | waitEntry, notifyCh := waiter.NewChannelEntry(nil) 125 | wq.EventRegister(&waitEntry, waiter.EventOut) 126 | terr := ep.Connect(remote) 127 | if terr == tcpip.ErrConnectStarted { 128 | log.Println("@main cmd/tcp: Connect is pending...") 129 | <-notifyCh 130 | terr = ep.GetSockOpt(tcpip.ErrorOption{}) 131 | } 132 | wq.EventUnregister(&waitEntry) 133 | if terr != nil { 134 | log.Fatal("@main cmd/tcp: Unable to connect: ", terr) 135 | } 136 | log.Println("@main cmd/tcp: Connected") 137 | time.Sleep(1 * time.Second) 138 | 139 | ep.Close() 140 | log.Println("@main cmd/tcp:tcp disconnected") 141 | time.Sleep(3 * time.Second) 142 | 143 | } 144 | -------------------------------------------------------------------------------- /cmd/transport/tcp/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/brewlin/net-protocol/config" 6 | "github.com/brewlin/net-protocol/internal/endpoint" 7 | "github.com/brewlin/net-protocol/pkg/logging" 8 | "log" 9 | 10 | "github.com/brewlin/net-protocol/pkg/waiter" 11 | 12 | "github.com/brewlin/net-protocol/protocol/network/ipv4" 13 | "github.com/brewlin/net-protocol/protocol/transport/tcp" 14 | "github.com/brewlin/net-protocol/stack" 15 | 16 | tcpip "github.com/brewlin/net-protocol/protocol" 17 | ) 18 | 19 | 20 | func init() { 21 | logging.Setup() 22 | } 23 | 24 | func main() { 25 | s := endpoint.NewEndpoint() 26 | tcpServer(s) 27 | 28 | } 29 | 30 | func tcpServer(s *stack.Stack) { 31 | var wq waiter.Queue 32 | //新建一个tcp端 33 | ep, e := s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 34 | if e != nil { 35 | log.Fatal(e) 36 | } 37 | //绑定本地端口 38 | if err := ep.Bind(tcpip.FullAddress{0, "", config.LocalPort}, nil); err != nil { 39 | log.Fatal("@main :Bind failed: ", err) 40 | } 41 | //监听tcp 42 | if err := ep.Listen(10); err != nil { 43 | log.Fatal("@main :Listen failed: ", err) 44 | } 45 | //等待连接 出现 46 | waitEntry, notifyCh := waiter.NewChannelEntry(nil) 47 | wq.EventRegister(&waitEntry, waiter.EventIn) 48 | defer wq.EventUnregister(&waitEntry) 49 | 50 | for { 51 | n, q, err := ep.Accept() 52 | if err != nil { 53 | if err == tcpip.ErrWouldBlock { 54 | fmt.Println("@main server:", " now waiting to new client connection ...") 55 | <-notifyCh 56 | continue 57 | } 58 | fmt.Println("@main server: Accept() failed: ", err) 59 | panic(err) 60 | } 61 | addr, _ := n.GetRemoteAddress() 62 | fmt.Println("@main server: new client connection : ", addr) 63 | 64 | go dispatch(n, q, addr) 65 | } 66 | } 67 | func dispatch(e tcpip.Endpoint, wq *waiter.Queue, addr tcpip.FullAddress) { 68 | 69 | waitEntry, notifyCh := waiter.NewChannelEntry(nil) 70 | wq.EventRegister(&waitEntry, waiter.EventIn) 71 | defer wq.EventUnregister(&waitEntry) 72 | for { 73 | v, c, err := e.Read(&addr) 74 | if err != nil { 75 | if err == tcpip.ErrWouldBlock { 76 | fmt.Println("@main dispatch: waiting new event trigger ...") 77 | <-notifyCh 78 | continue 79 | } 80 | fmt.Println("@main dispatch:tcp read got error", err) 81 | break 82 | } 83 | fmt.Println("@main dispatch: recv ", v, c) 84 | a, b, er := e.Write(tcpip.SlicePayload(v), tcpip.WriteOptions{To: &addr}) 85 | fmt.Println("@main dispatch: write to client res: ", a, b, er) 86 | } 87 | e.Close() 88 | } 89 | -------------------------------------------------------------------------------- /cmd/transport/udp/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | _ "github.com/brewlin/net-protocol/pkg/logging" 7 | "github.com/brewlin/net-protocol/protocol/transport/udp/client" 8 | ) 9 | 10 | func main() { 11 | con := client.NewClient("10.0.2.15", 9000) 12 | defer con.Close() 13 | 14 | if err := con.Connect(); err != nil { 15 | fmt.Println(err) 16 | } 17 | con.Write([]byte("send msg")) 18 | res, err := con.Read() 19 | if err != nil { 20 | fmt.Println(err) 21 | con.Close() 22 | return 23 | } 24 | // var p [8]byte 25 | // res, _ := con.Readn(p[:1]) 26 | fmt.Println(string(res)) 27 | 28 | } 29 | -------------------------------------------------------------------------------- /cmd/transport/udp/net_client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "log" 6 | "net" 7 | ) 8 | 9 | func main() { 10 | var ( 11 | addr = flag.String("a", "192.168.1.1:9000", "udp dst address") 12 | ) 13 | flag.Parse() 14 | log.SetFlags(log.Lshortfile) 15 | 16 | udpAddr, err := net.ResolveUDPAddr("udp", *addr) 17 | if err != nil { 18 | panic(err) 19 | } 20 | //建立udp连接 21 | conn, err := net.DialUDP("udp", nil, udpAddr) 22 | if err != nil { 23 | panic(err) 24 | } 25 | 26 | send := []byte("hello") 27 | recv := make([]byte, 10) 28 | if _, err := conn.Write(send); err != nil { 29 | log.Fatal(err) 30 | } 31 | log.Printf("send:%s", string(send)) 32 | 33 | rn, _, err := conn.ReadFrom(recv) 34 | log.Println(rn) 35 | if err != nil { 36 | panic(err) 37 | } 38 | log.Printf("recv :%s", string(recv[:rn])) 39 | } 40 | -------------------------------------------------------------------------------- /cmd/transport/udp/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "github.com/brewlin/net-protocol/config" 8 | "github.com/brewlin/net-protocol/internal/endpoint" 9 | "github.com/brewlin/net-protocol/pkg/logging" 10 | "github.com/brewlin/net-protocol/pkg/waiter" 11 | "github.com/brewlin/net-protocol/protocol/network/ipv4" 12 | "github.com/brewlin/net-protocol/protocol/transport/udp" 13 | "github.com/brewlin/net-protocol/stack" 14 | 15 | tcpip "github.com/brewlin/net-protocol/protocol" 16 | ) 17 | 18 | func init() { 19 | logging.Setup() 20 | } 21 | func main() { 22 | s := endpoint.NewEndpoint() 23 | 24 | echo(s) 25 | 26 | } 27 | func echo(s *stack.Stack) { 28 | var wq waiter.Queue 29 | //新建一个UDP端 30 | ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 31 | if err != nil { 32 | log.Fatal(err) 33 | } 34 | //绑定本地端口 35 | if err := ep.Bind(tcpip.FullAddress{1, config.LocalAddres, config.LocalPort}, nil); err != nil { 36 | log.Fatal("@main : bind failed :", err) 37 | } 38 | defer ep.Close() 39 | //创建队列 通知 channel 40 | waitEntry, notifych := waiter.NewChannelEntry(nil) 41 | wq.EventRegister(&waitEntry, waiter.EventIn) 42 | defer wq.EventUnregister(&waitEntry) 43 | 44 | var saddr tcpip.FullAddress 45 | 46 | for { 47 | v, _, err := ep.Read(&saddr) 48 | if err != nil { 49 | if err == tcpip.ErrWouldBlock { 50 | <-notifych 51 | continue 52 | } 53 | return 54 | } 55 | fmt.Printf("@main :read and write data:%s %v", string(v), saddr) 56 | _, _, err = ep.Write(tcpip.SlicePayload(v), tcpip.WriteOptions{To: &saddr}) 57 | if err == tcpip.ErrWouldBlock { 58 | <-notifych 59 | } 60 | if err != nil && err != tcpip.ErrWouldBlock { 61 | log.Fatal(err) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /cmd/udp.md: -------------------------------------------------------------------------------- 1 | ## udp 实验 2 | 启动网卡,注册相关协议 以太网协议、arp协议、icmp协议、udp协议、初始化端口池 3 | ``` 4 | cd udp/server; 5 | go build 6 | ./server tap1 192.168.1.0/24 192.168.1.1 9000 7 | endpoint.go:89: 注册链路层设备, new endpoint 8 | 9 | //启动网卡 进入事件循环 10 | registration.go:364: @协议栈 stack: register 注册链路层设备LinkEndpointID: 1 11 | stack.go:506: @网卡 stack: 新建网卡对象,并启动网卡事件 12 | nic.go:225: @网卡 nic: 在nic网卡上添加网络层,注册和初始化网络协议 protocol: 2048 addr: 192 13 | nic.go:225: @网卡 nic: 在nic网卡上添加网络层,注册和初始化网络协议 protocol: 2054 addr: 617 14 | stack.go:777: @网卡 stack: 协议解析 nicid: 1 protocol: 2048 addr: 192.168.1.1 15 | ports.go:131: @端口 port: 协议绑定端口 new transport: 17, port: 9000 16 | endpoint.go:190: @链路层 fdbased: dispatch 调度进行事件循环接受物理网卡数据 dispatchLoop 17 | //等待接收数据 18 | endpoint.go:208: @链路层 fdbased: step1 物理网卡接受数据read 42 bytes 19 | endpoint.go:226: @链路层 fdbased: step2 解析以太网协议: [255 255 255 255 255 255 146 234 254 168 251 25 8 6 0 1 8 0 6 4 0 1 146 234 254 168 251 25 10 105 121 88 0 0 0 0 0 0 192 168 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 2054 92:ea:fe:a8:fb:19 ff:ff:ff:ff:ff:ff 20 | nic.go:432: @网卡 nic: step3 nic网卡解析以太网协议,分发到对应的 网络层 协议处理 21 | arp.go:92: @网络层 arp: step1 : 解析arp数据包,包括arp请求和响应 22 | arp.go:103: @网络层 arp: step2 : 解析arp请求 23 | stack.go:777: @网卡 stack: 协议解析 nicid: 1 protocol: 2048 addr: 192.168.1.1 24 | arp.go:115: @网络层 arp: reply: 发送arp回复 25 | endpoint.go:116: @链路层: fdbased 写入网卡数据 0x4c6900 26 | linkaddrcache.go:152: @路由表 route: linkaddrcache 路由表缓存 1:10.105.121.88:0-92:ea:fe:a8:fb:19 27 | endpoint.go:208: @链路层 fdbased: step1 物理网卡接受数据read 47 bytes 28 | endpoint.go:226: @链路层 fdbased: step2 解析以太网协议: [1 1 1 1 1 1 146 234 254 168 251 25 8 0 69 0 0 33 162 77 64 0 64 17 83 20 10 105 121 88 192 168 1 1 157 87 35 40 0 13 182 23 104 101 108 108 111 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 2048 92:ea:fe:a8:fb:19 01:01:01:01:01:01 29 | nic.go:432: @网卡 nic: step3 nic网卡解析以太网协议,分发到对应的 网络层 协议处理 30 | ipv4.go:159: @网络层 ipv4: handlePacket 数据包处理 31 | ipv4.go:195: @网络层 ipv4: handlePacket 分发协议处理,recv ipv4 packet 33 bytes, proto: 0x11 32 | endpoint.go:923: @传输层 udp: handlepacket 从网络层接收到udp数据包 进行处理 33 | endpoint.go:977: @传输层 udp: recv udp 13 bytes 34 | main.go:150: @main :read and write data:hello 35 | endpoint.go:361: @传输层 udp: 写入udp数据 netProto: 0x800 36 | endpoint.go:561: @传输层 udp: 传输层 udp协议 封装头部信息,发送给网络层 sendudp 37 | ipv4.go:151: @网络层 ipv4: 接受传输层数据 封装ip头部信息,写入链路层网卡数据 send ipv4 packet 33 bytes, proto: 0x11 38 | endpoint.go:116: @链路层: fdbased 写入网卡数据 0x4c6900 39 | 40 | ``` 41 | client调用 42 | ``` 43 | cd udp/client 44 | go build 45 | ./client 46 | 47 | main.go:30: send:hello 48 | main.go:37: recv :hello 49 | 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /cmd/websocket.md: -------------------------------------------------------------------------------- 1 | # websocket协议 2 | ``` 3 | 基于http协议,封装websocket协议, 接管http流程 4 | ``` 5 | ## start 6 | ``` 7 | cd application/websocket 8 | go build 9 | sudo ./websocket 10 | 11 | 12 | ``` 13 | ## @websocketserver.go 14 | ``` 15 | package main 16 | 17 | import ( 18 | "fmt" 19 | "log" 20 | 21 | "github.com/brewlin/net-protocol/pkg/logging" 22 | "github.com/brewlin/net-protocol/protocol/application/http" 23 | "github.com/brewlin/net-protocol/protocol/application/websocket" 24 | ) 25 | 26 | func init() { 27 | logging.Setup() 28 | } 29 | func main() { 30 | serv := http.NewHTTP("tap1", "192.168.1.0/24", "192.168.1.1", "9502") 31 | serv.HandleFunc("/ws", echo) 32 | 33 | serv.HandleFunc("/", func(request *http.Request, response *http.Response) { 34 | response.End("hello") 35 | }) 36 | fmt.Println("@main: server is start ip:192.168.1.1 port:9502 ") 37 | serv.ListenAndServ() 38 | } 39 | 40 | //websocket处理器 41 | func echo(r *http.Request, w *http.Response) { 42 | fmt.Println("got http request ; start to upgrade websocket protocol....") 43 | //协议升级 c *websocket.Conn 44 | c, err := websocket.Upgrade(r, w) 45 | if err != nil { 46 | //升级协议失败,直接return 交由http处理响应 47 | fmt.Println("Upgrade error:", err) 48 | return 49 | } 50 | defer c.Close() 51 | //循环处理数据,接受数据,然后返回 52 | for { 53 | message, err := c.ReadData() 54 | if err != nil { 55 | log.Println("read:", err) 56 | break 57 | } 58 | fmt.Println("recv client msg:", string(message)) 59 | // c.SendData(message ) 60 | c.SendData([]byte("hello")) 61 | } 62 | } 63 | 64 | ``` 65 | ## demo 66 | ![](/resource/websocket.png) -------------------------------------------------------------------------------- /config/net.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "flag" 5 | "net" 6 | 7 | tcpip "github.com/brewlin/net-protocol/protocol" 8 | ) 9 | 10 | //mac地址 11 | var Mac = flag.String("mac", "aa:00:01:01:01:01", "mac address to use in tap device") 12 | 13 | //网卡名 14 | var NicName = "tap" 15 | 16 | //路由网段 17 | var Cidrname = "192.168.1.0/24" 18 | 19 | //localip 20 | var LocalAddres = tcpip.Address(net.ParseIP("192.168.1.1").To4()) 21 | 22 | //物理网卡名,ip 作为连通外网的网关使用,不填默认自动获取 23 | var HardwardIp = "" 24 | var HardwardName = "" 25 | 26 | var LocalPort uint16 = 9000 27 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/brewlin/net-protocol 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /http-api.md: -------------------------------------------------------------------------------- 1 | # http protocol api 2 | ## @start 3 | ``` 4 | //新建一个初始化server,(底层 会创建一个tap网卡并注册 路由,arp缓存等),初始化端口机制,添加9502到端口表 5 | serv := http.NewHTTP("tap1", "192.168.1.0/24", "192.168.1.1", "9502") 6 | //添加路由,当对应请求到来时,分发到自定义回调函数中处理 7 | serv.HandleFunc("/", func(request *http.Request, response *http.Response) 8 | //赋值给将要发送响应给客户端的 buf 9 | Response.End("string"); 10 | //启动监听网卡、启动tcp、启动dispatch 分发事件并阻塞 等待client连接。。 11 | serv.ListenAndServ() 12 | ``` -------------------------------------------------------------------------------- /internal/endpoint/endpoint.go: -------------------------------------------------------------------------------- 1 | package endpoint 2 | 3 | import ( 4 | "github.com/brewlin/net-protocol/config" 5 | tcpip "github.com/brewlin/net-protocol/protocol" 6 | "github.com/brewlin/net-protocol/protocol/link/fdbased" 7 | "github.com/brewlin/net-protocol/protocol/link/tuntap" 8 | "github.com/brewlin/net-protocol/protocol/network/arp" 9 | "github.com/brewlin/net-protocol/protocol/network/ipv4" 10 | "github.com/brewlin/net-protocol/protocol/transport/tcp" 11 | "github.com/brewlin/net-protocol/protocol/transport/udp" 12 | "github.com/brewlin/net-protocol/stack" 13 | "github.com/brewlin/net-protocol/stack/stackinit" 14 | "log" 15 | "net" 16 | _ "github.com/brewlin/net-protocol/stack/stackinit" 17 | "strings" 18 | ) 19 | //NewEndpoint 新建一个网卡端,默认注册 udp tcp arp ipv4等协议 20 | func NewEndpoint()*stack.Stack{ 21 | //如果已经存在 p 指向的stack 则不需要在初始化 22 | if stack.Pstack != nil { 23 | stackinit.AddRoute(config.LocalAddres) 24 | return stack.Pstack 25 | } 26 | log.Printf("tap :%v", config.NicName) 27 | 28 | //解析mac地址 29 | maddr, err := net.ParseMAC(*config.Mac) 30 | if err != nil { 31 | log.Fatal(*config.Mac) 32 | } 33 | 34 | //虚拟网卡配置 35 | conf := &tuntap.Config{ 36 | Name: config.NicName, 37 | Mode: tuntap.TAP, 38 | } 39 | var fd int 40 | //新建虚拟网卡 41 | fd, err = tuntap.NewNetDev(conf) 42 | if err != nil { 43 | log.Fatal(err) 44 | } 45 | //抽象网卡层接口 46 | linkID := fdbased.New(&fdbased.Options{ 47 | FD: fd, 48 | MTU: 1500, 49 | Address: tcpip.LinkAddress(maddr), 50 | ResolutionRequired: true, 51 | }) 52 | //新建相关协议的协议栈 53 | s := stack.New([]string{ipv4.ProtocolName, arp.ProtocolName}, []string{tcp.ProtocolName, udp.ProtocolName}, stack.Options{}) 54 | //新建抽象网卡 55 | if err := s.CreateNamedNIC(1, "vnic1", linkID); err != nil { 56 | log.Fatal(err) 57 | } 58 | var proto = ipv4.ProtocolNumber 59 | //在该协议栈上添加和注册相关的网络层协议 也就是注册本地地址 60 | if err := s.AddAddress(1, proto, config.LocalAddres); err != nil { 61 | log.Fatal(err) 62 | } 63 | //在该协议栈上添加和注册arp协议 64 | if err := s.AddAddress(1, arp.ProtocolNumber, arp.ProtocolAddress); err != nil { 65 | log.Fatal(err) 66 | } 67 | //添加默认路由 68 | s.SetRouteTable([]tcpip.Route{ 69 | { 70 | Destination: tcpip.Address(strings.Repeat("\x00", len(config.LocalAddres))), 71 | Mask: tcpip.AddressMask(strings.Repeat("\x00", len(config.LocalAddres))), 72 | Gateway: "", 73 | NIC: 1, 74 | }, 75 | }) 76 | return s 77 | 78 | } -------------------------------------------------------------------------------- /internal/socket/socket.go: -------------------------------------------------------------------------------- 1 | package socket 2 | 3 | import ( 4 | "github.com/brewlin/net-protocol/pkg/waiter" 5 | tcpip "github.com/brewlin/net-protocol/protocol" 6 | ) 7 | 8 | //Socket ***client 9 | type Socket interface { 10 | //Write 向对端写入数据 11 | Write(buf []byte) error 12 | //Read 读取单次所有数据包 不等待直接返回 13 | Read()([]byte,error) 14 | //Readn 读取n字节 15 | Readn(p []byte)(int,error) 16 | //Close 17 | Close() 18 | //GetAddr 获取客户端ip地址 19 | GetAddr()tcpip.Address 20 | //GetRemoteAddr 获取远程客户端ip地址 21 | GetRemoteAddr()*tcpip.FullAddress 22 | //GetQueue 获取接收时间队列 23 | GetQueue()*waiter.Queue 24 | GetNotify()chan struct{} 25 | } 26 | -------------------------------------------------------------------------------- /pkg/buffer/prependable.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package buffer 16 | 17 | // Prependable is a buffer that grows backwards, that is, more data can be 18 | // prepended to it. It is useful when building networking packets, where each 19 | // protocol adds its own headers to the front of the higher-level protocol 20 | // header and payload; for example, TCP would prepend its header to the payload, 21 | // then IP would prepend its own, then ethernet. 22 | type Prependable struct { 23 | // Buf is the buffer backing the prependable buffer. 24 | buf View 25 | 26 | // usedIdx is the index where the used part of the buffer begins. 27 | usedIdx int 28 | } 29 | 30 | // NewPrependable allocates a new prependable buffer with the given size. 31 | func NewPrependable(size int) Prependable { 32 | return Prependable{buf: NewView(size), usedIdx: size} 33 | } 34 | 35 | // NewPrependableFromView creates an entirely-used Prependable from a View. 36 | // 37 | // NewPrependableFromView takes ownership of v. Note that since the entire 38 | // prependable is used, further attempts to call Prepend will note that size > 39 | // p.usedIdx and return nil. 40 | func NewPrependableFromView(v View) Prependable { 41 | return Prependable{buf: v, usedIdx: 0} 42 | } 43 | 44 | // View returns a View of the backing buffer that contains all prepended 45 | // data so far. 46 | func (p Prependable) View() View { 47 | return p.buf[p.usedIdx:] 48 | } 49 | 50 | // UsedLength returns the number of bytes used so far. 51 | func (p Prependable) UsedLength() int { 52 | return len(p.buf) - p.usedIdx 53 | } 54 | 55 | // Prepend reserves the requested space in front of the buffer, returning a 56 | // slice that represents the reserved space. 57 | func (p *Prependable) Prepend(size int) []byte { 58 | if size > p.usedIdx { 59 | return nil 60 | } 61 | 62 | p.usedIdx -= size 63 | return p.View()[:size:size] 64 | } 65 | -------------------------------------------------------------------------------- /pkg/buffer/string.go: -------------------------------------------------------------------------------- 1 | package buffer 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | ) 7 | 8 | func GetRandomString(l int) string { 9 | str := "0123456789abcdefghijklmnopqrstuvwxyz" 10 | bytes := []byte(str) 11 | result := []byte{} 12 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 13 | for i := 0; i < l; i++ { 14 | result = append(result, bytes[r.Intn(len(bytes))]) 15 | } 16 | return string(result) 17 | } -------------------------------------------------------------------------------- /pkg/buffer/url.go: -------------------------------------------------------------------------------- 1 | package buffer 2 | 3 | import ( 4 | "errors" 5 | "log" 6 | "regexp" 7 | "strconv" 8 | ) 9 | //ResolveUrl parse url to ip port path 10 | //http://10.0.2.15/test 11 | //http://10.0.2.15:8080/ 12 | func ParseUrl(url string)(ip string,port int,path string,err error){ 13 | // ipex := regexp.MustCompile(`http://(.*?)(:(\d{2,4}))?(/.*)`) 14 | egex := regexp.MustCompile(`http://(\d+\.\d+\.\d+\.\d+)(:(\d{2,4}))?(/.*)`) 15 | regex := egex.FindAllStringSubmatch(url,-1) 16 | if len(regex) != 1 { 17 | return ip,port,path,errors.New("url is invalid") 18 | } 19 | urlPar := regex[0] 20 | var oport string 21 | ip,oport,path = urlPar[1],urlPar[3],urlPar[4] 22 | log.Println(urlPar) 23 | if oport == "" { 24 | oport = "80" 25 | } 26 | port,err = strconv.Atoi(oport) 27 | return 28 | } -------------------------------------------------------------------------------- /pkg/logging/log.go: -------------------------------------------------------------------------------- 1 | package logging 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | // Setup initialize the log instance 9 | func Setup() { 10 | file := "./log.txt" 11 | logFile, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766) 12 | if err != nil { 13 | panic(err) 14 | } 15 | log.SetOutput(logFile) 16 | log.SetFlags(log.Lshortfile) 17 | return 18 | } 19 | func init(){ 20 | Setup() 21 | } 22 | -------------------------------------------------------------------------------- /pkg/rand/rand.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package rand implements a cryptographically secure pseudorandom number 16 | // generator. 17 | package rand 18 | 19 | import "crypto/rand" 20 | 21 | // Reader is the default reader. 22 | var Reader = rand.Reader 23 | 24 | // Read implements io.Reader.Read. 25 | func Read(b []byte) (int, error) { 26 | return rand.Read(b) 27 | } 28 | -------------------------------------------------------------------------------- /pkg/reexec/README.md: -------------------------------------------------------------------------------- 1 | ## reexec 2 | 3 | The `reexec` package facilitates the busybox style reexec of the docker binary that we require because 4 | of the forking limitations of using Go. Handlers can be registered with a name and the argv 0 of 5 | the exec of the binary will be used to find and execute custom init paths. 6 | -------------------------------------------------------------------------------- /pkg/reexec/command_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | package reexec 4 | 5 | import ( 6 | "os/exec" 7 | "syscall" 8 | ) 9 | 10 | // Self returns the path to the current process's binary. 11 | // Returns "/proc/self/exe". 12 | func Self() string { 13 | return "/proc/self/exe" 14 | } 15 | 16 | // Command returns *exec.Cmd which have Path as current binary. Also it setting 17 | // SysProcAttr.Pdeathsig to SIGTERM. 18 | // This will use the in-memory version (/proc/self/exe) of the current binary, 19 | // it is thus safe to delete or replace the on-disk binary (os.Args[0]). 20 | func Command(args ...string) *exec.Cmd { 21 | return &exec.Cmd{ 22 | Path: Self(), 23 | Args: args, 24 | SysProcAttr: &syscall.SysProcAttr{ 25 | Pdeathsig: syscall.SIGTERM, 26 | }, 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/reexec/command_unix.go: -------------------------------------------------------------------------------- 1 | // +build freebsd solaris 2 | 3 | package reexec 4 | 5 | import ( 6 | "os/exec" 7 | ) 8 | 9 | // Self returns the path to the current process's binary. 10 | // Uses os.Args[0]. 11 | func Self() string { 12 | return naiveSelf() 13 | } 14 | 15 | // Command returns *exec.Cmd which have Path as current binary. 16 | // For example if current binary is "docker" at "/usr/bin/", then cmd.Path will 17 | // be set to "/usr/bin/docker". 18 | func Command(args ...string) *exec.Cmd { 19 | return &exec.Cmd{ 20 | Path: Self(), 21 | Args: args, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pkg/reexec/command_unsupported.go: -------------------------------------------------------------------------------- 1 | // +build !linux,!windows,!freebsd,!solaris 2 | 3 | package reexec 4 | 5 | import ( 6 | "os/exec" 7 | ) 8 | 9 | // Command is unsupported on operating systems apart from Linux and Windows. 10 | func Command(args ...string) *exec.Cmd { 11 | return nil 12 | } 13 | -------------------------------------------------------------------------------- /pkg/reexec/command_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package reexec 4 | 5 | import ( 6 | "os/exec" 7 | ) 8 | 9 | // Self returns the path to the current process's binary. 10 | // Uses os.Args[0]. 11 | func Self() string { 12 | return naiveSelf() 13 | } 14 | 15 | // Command returns *exec.Cmd which have Path as current binary. 16 | // For example if current binary is "docker.exe" at "C:\", then cmd.Path will 17 | // be set to "C:\docker.exe". 18 | func Command(args ...string) *exec.Cmd { 19 | return &exec.Cmd{ 20 | Path: Self(), 21 | Args: args, 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pkg/reexec/reexec.go: -------------------------------------------------------------------------------- 1 | package reexec 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "path/filepath" 8 | ) 9 | 10 | var registeredInitializers = make(map[string]func()) 11 | 12 | // Register adds an initialization func under the specified name 13 | func Register(name string, initializer func()) { 14 | if _, exists := registeredInitializers[name]; exists { 15 | panic(fmt.Sprintf("reexec func already registered under name %q", name)) 16 | } 17 | 18 | registeredInitializers[name] = initializer 19 | } 20 | 21 | // Init is called as the first part of the exec process and returns true if an 22 | // initialization function was called. 23 | func Init() bool { 24 | initializer, exists := registeredInitializers[os.Args[0]] 25 | if exists { 26 | initializer() 27 | 28 | return true 29 | } 30 | return false 31 | } 32 | 33 | func naiveSelf() string { 34 | name := os.Args[0] 35 | if filepath.Base(name) == name { 36 | if lp, err := exec.LookPath(name); err == nil { 37 | return lp 38 | } 39 | } 40 | // handle conversion of relative paths to absolute 41 | if absName, err := filepath.Abs(name); err == nil { 42 | return absName 43 | } 44 | // if we couldn't get absolute name, return original 45 | // (NOTE: Go only errors on Abs() if os.Getwd fails) 46 | return name 47 | } 48 | -------------------------------------------------------------------------------- /pkg/seqnum/seqnum.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package seqnum defines the types and methods for TCP sequence numbers such 16 | // that they fit in 32-bit words and work properly when overflows occur. 17 | package seqnum 18 | 19 | // Value represents the value of a sequence number. 20 | type Value uint32 21 | 22 | // Size represents the size (length) of a sequence number window. 23 | type Size uint32 24 | 25 | // LessThan checks if v is before w, i.e., v < w. 26 | func (v Value) LessThan(w Value) bool { 27 | return int32(v-w) < 0 28 | } 29 | 30 | // LessThanEq returns true if v==w or v is before i.e., v < w. 31 | func (v Value) LessThanEq(w Value) bool { 32 | if v == w { 33 | return true 34 | } 35 | return v.LessThan(w) 36 | } 37 | 38 | // InRange checks if v is in the range [a,b), i.e., a <= v < b. 39 | func (v Value) InRange(a, b Value) bool { 40 | return v-a < b-a 41 | } 42 | 43 | // InWindow checks if v is in the window that starts at 'first' and spans 'size' 44 | // sequence numbers. 45 | func (v Value) InWindow(first Value, size Size) bool { 46 | return v.InRange(first, first.Add(size)) 47 | } 48 | 49 | // Overlap checks if the window [a,a+b) overlaps with the window [x, x+y). 50 | func Overlap(a Value, b Size, x Value, y Size) bool { 51 | return a.LessThan(x.Add(y)) && x.LessThan(a.Add(b)) 52 | } 53 | 54 | // Add calculates the sequence number following the [v, v+s) window. 55 | func (v Value) Add(s Size) Value { 56 | return v + Value(s) 57 | } 58 | 59 | // Size calculates the size of the window defined by [v, w). 60 | func (v Value) Size(w Value) Size { 61 | return Size(w - v) 62 | } 63 | 64 | // UpdateForward updates v such that it becomes v + s. 65 | func (v *Value) UpdateForward(s Size) { 66 | *v += Value(s) 67 | } 68 | -------------------------------------------------------------------------------- /pkg/sleep/commit_amd64.s: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "textflag.h" 16 | 17 | #define preparingG 1 18 | 19 | // See commit_noasm.go for a description of commitSleep. 20 | // 21 | // func commitSleep(g uintptr, waitingG *uintptr) bool 22 | TEXT ·commitSleep(SB),NOSPLIT,$0-24 23 | MOVQ waitingG+8(FP), CX 24 | MOVQ g+0(FP), DX 25 | 26 | // Store the G in waitingG if it's still preparingG. If it's anything 27 | // else it means a waker has aborted the sleep. 28 | MOVQ $preparingG, AX 29 | LOCK 30 | CMPXCHGQ DX, 0(CX) 31 | 32 | SETEQ AX 33 | MOVB AX, ret+16(FP) 34 | 35 | RET 36 | -------------------------------------------------------------------------------- /pkg/sleep/commit_asm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build amd64 16 | 17 | package sleep 18 | 19 | // See commit_noasm.go for a description of commitSleep. 20 | func commitSleep(g uintptr, waitingG *uintptr) bool 21 | -------------------------------------------------------------------------------- /pkg/sleep/commit_noasm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build !race 16 | // +build !amd64 17 | 18 | package sleep 19 | 20 | import "sync/atomic" 21 | 22 | // commitSleep signals to wakers that the given g is now sleeping. Wakers can 23 | // then fetch it and wake it. 24 | // 25 | // The commit may fail if wakers have been asserted after our last check, in 26 | // which case they will have set s.waitingG to zero. 27 | // 28 | // It is written in assembly because it is called from g0, so it doesn't have 29 | // a race context. 30 | func commitSleep(g uintptr, waitingG *uintptr) bool { 31 | for { 32 | // Check if the wait was aborted. 33 | if atomic.LoadUintptr(waitingG) == 0 { 34 | return false 35 | } 36 | 37 | // Try to store the G so that wakers know who to wake. 38 | if atomic.CompareAndSwapUintptr(waitingG, preparingG, g) { 39 | return true 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pkg/sleep/empty.s: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Empty assembly file so empty func definitions work. 16 | -------------------------------------------------------------------------------- /pkg/syscall/c_net/net.go: -------------------------------------------------------------------------------- 1 | package c_net 2 | 3 | /* 4 | #include 5 | #include 6 | #include 7 | #include "network.h" 8 | */ 9 | import "C" 10 | import ( 11 | "errors" 12 | "syscall" 13 | "unsafe" 14 | ) 15 | 16 | //LxcBridgeAttach 17 | //bind the veth to bridge 18 | func LxcBridgeAttach(bridge, ifname string) (state int, err error) { 19 | b := C.CString(bridge) 20 | defer C.free(unsafe.Pointer(b)) 21 | 22 | i := C.CString(ifname) 23 | defer C.free(unsafe.Pointer(i)) 24 | cstate := C.lxc_bridge_attach(b,i) 25 | 26 | state = int(cstate) 27 | if cstate != 0 { 28 | err = errors.New(syscall.Errno(cstate).Error()) 29 | } 30 | return 31 | } 32 | 33 | //GetHardwareAddr 34 | func GetHardwareAddr(name string) (string, error) { 35 | n := C.CString(name) 36 | defer C.free(unsafe.Pointer((n))) 37 | 38 | res := C.get_hardware_addr(n) 39 | defer C.free(unsafe.Pointer(res)) 40 | mac := C.GoString(res) 41 | return mac, nil 42 | } 43 | -------------------------------------------------------------------------------- /pkg/syscall/c_net/net_test.go: -------------------------------------------------------------------------------- 1 | package c_net 2 | 3 | import "testing" 4 | 5 | func TestLxcBridgeAttach(t *testing.T) { 6 | code,err := LxcBridgeAttach("docker0","tap0") 7 | if err != nil { 8 | t.Fatal(err) 9 | } 10 | t.Log(code) 11 | } 12 | 13 | func TestGetHardwareAddr(t *testing.T) { 14 | res,err := GetHardwareAddr("tap0") 15 | if err != nil { 16 | t.Log(err) 17 | t.Fatal(err) 18 | } 19 | if len(res) != 6 { 20 | t.Fatal(err) 21 | } 22 | t.Log(res) 23 | } -------------------------------------------------------------------------------- /pkg/syscall/c_net/network.h: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | extern "C" 3 | { 4 | #endif 5 | #include 6 | int netdev_set_flag(const char *name, int flag); 7 | int lxc_netdev_up(const char *name); 8 | int lxc_netdev_down(const char *name); 9 | int lxc_veth_create(const char *name1, const char *name2); 10 | int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char* ifname); 11 | int lxc_netdev_move_by_name(const char *ifname, pid_t pid, const char* newname); 12 | int setup_private_host_hw_addr(char *veth1); 13 | int lxc_bridge_attach(const char *bridge, const char *ifname); 14 | int lxc_convert_mac(char *macaddr, struct sockaddr *sockaddr); 15 | static int ip_addr_add(int family, int ifindex, 16 | void *addr, void *bcast, void *acast, int prefix); 17 | int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr, 18 | struct in_addr *bcast, int prefix); 19 | static int ip_gateway_add(int family, int ifindex, void *gw); 20 | int lxc_ipv4_gateway_add(int ifindex, struct in_addr *gw); 21 | static int ip_route_dest_add(int family, int ifindex, void *dest); 22 | int lxc_ipv4_dest_add(int ifindex, struct in_addr *dest); 23 | int setup_hw_addr(char *hwaddr, const char *ifname); 24 | char *lxc_mkifname(char *); 25 | int lxc_netdev_delete_by_index(int ifindex); 26 | int lxc_netdev_delete_by_name(const char *name); 27 | void new_hwaddr(char *hwaddr); 28 | //get mac addr 29 | char *get_hardware_addr(char *name); 30 | 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif -------------------------------------------------------------------------------- /pkg/syscall/pivot_root.go: -------------------------------------------------------------------------------- 1 | package syscall 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "syscall" 8 | ) 9 | 10 | func PivotRoot(newroot string) error { 11 | putold := filepath.Join(newroot, "/.pivot_root") 12 | // bind mount newroot to itself - this is a slight hack 13 | // needed to work around a pivot_root requirement 14 | if err := syscall.Mount( 15 | newroot, 16 | newroot, 17 | "", 18 | syscall.MS_BIND|syscall.MS_REC, 19 | "", 20 | ); err != nil { 21 | fmt.Println(err) 22 | return err 23 | } 24 | 25 | // create putold directory 26 | if err := os.MkdirAll(putold, 0700); err != nil { 27 | return err 28 | } 29 | 30 | // call pivot_root 31 | if err := syscall.PivotRoot(newroot, putold); err != nil { 32 | return err 33 | } 34 | 35 | // ensure current working directory is set to new root 36 | if err := os.Chdir("/"); err != nil { 37 | return err 38 | } 39 | 40 | // umount putold, which now lives at /.pivot_root 41 | putold = "/.pivot_root" 42 | if err := syscall.Unmount( 43 | putold, 44 | syscall.MNT_DETACH, 45 | ); err != nil { 46 | return err 47 | } 48 | 49 | // remove putold 50 | if err := os.RemoveAll(putold); err != nil { 51 | return err 52 | } 53 | 54 | return nil 55 | } 56 | func ExitIfRootfsNotFound(rootfsPath string) { 57 | if _, err := os.Stat(rootfsPath); os.IsNotExist(err) { 58 | fmt.Println(err) 59 | os.Exit(1) 60 | } 61 | } 62 | func MountProc(newroot string) error { 63 | source := "proc" 64 | target := filepath.Join(newroot, "/proc") 65 | fstype := "proc" 66 | flags := 0 67 | data := "" 68 | 69 | os.MkdirAll(target, 0755) 70 | if err := syscall.Mount( 71 | source, 72 | target, 73 | fstype, 74 | uintptr(flags), 75 | data, 76 | ); err != nil { 77 | return err 78 | } 79 | 80 | return nil 81 | } 82 | func MountSys(newroot string) error { 83 | //source := "sys" 84 | target := filepath.Join(newroot, "/sys") 85 | fstype := "sysfs" 86 | flags := 0 87 | data := "" 88 | 89 | os.MkdirAll(target, 0755) 90 | if err := syscall.Mount( 91 | "none", 92 | target, 93 | fstype, 94 | uintptr(flags), 95 | data, 96 | ); err != nil { 97 | return err 98 | } 99 | 100 | return nil 101 | } -------------------------------------------------------------------------------- /pkg/tmutex/tmutex.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package tmutex provides the implementation of a mutex that implements an 16 | // efficient TryLock function in addition to Lock and Unlock. 17 | package tmutex 18 | 19 | import ( 20 | "sync/atomic" 21 | ) 22 | 23 | // Mutex is a mutual exclusion primitive that implements TryLock in addition 24 | // to Lock and Unlock. 25 | type Mutex struct { 26 | v int32 27 | ch chan struct{} 28 | } 29 | 30 | // Init initializes the mutex. 31 | func (m *Mutex) Init() { 32 | m.v = 1 33 | m.ch = make(chan struct{}, 1) 34 | } 35 | 36 | // Lock acquires the mutex. If it is currently held by another goroutine, Lock 37 | // will wait until it has a chance to acquire it. 38 | func (m *Mutex) Lock() { 39 | // Uncontended case. 40 | if atomic.AddInt32(&m.v, -1) == 0 { 41 | return 42 | } 43 | 44 | for { 45 | // Try to acquire the mutex again, at the same time making sure 46 | // that m.v is negative, which indicates to the owner of the 47 | // lock that it is contended, which will force it to try to wake 48 | // someone up when it releases the mutex. 49 | if v := atomic.LoadInt32(&m.v); v >= 0 && atomic.SwapInt32(&m.v, -1) == 1 { 50 | return 51 | } 52 | 53 | // Wait for the mutex to be released before trying again. 54 | <-m.ch 55 | } 56 | } 57 | 58 | // TryLock attempts to acquire the mutex without blocking. If the mutex is 59 | // currently held by another goroutine, it fails to acquire it and returns 60 | // false. 61 | func (m *Mutex) TryLock() bool { 62 | v := atomic.LoadInt32(&m.v) 63 | if v <= 0 { 64 | return false 65 | } 66 | return atomic.CompareAndSwapInt32(&m.v, 1, 0) 67 | } 68 | 69 | // Unlock releases the mutex. 70 | func (m *Mutex) Unlock() { 71 | if atomic.SwapInt32(&m.v, 1) == 0 { 72 | // There were no pending waiters. 73 | return 74 | } 75 | 76 | // Wake some waiter up. 77 | select { 78 | case m.ch <- struct{}{}: 79 | default: 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /protocol/application/dns/endopoint.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | _ "github.com/brewlin/net-protocol/pkg/logging" 5 | "github.com/brewlin/net-protocol/protocol/header" 6 | "github.com/brewlin/net-protocol/protocol/transport/udp/client" 7 | ) 8 | var gid uint16 = 0x0010 9 | 10 | type Endpoint struct { 11 | ID uint16 12 | Domain string 13 | 14 | //req data 15 | req *header.DNS 16 | resp *header.DNS 17 | 18 | answer *[]header.DNSResource 19 | 20 | c *client.Client 21 | } 22 | //NewEndpoint 23 | //support single domain query 24 | func NewEndpoint(domain string)*Endpoint{ 25 | id := gid + 1 26 | return &Endpoint{ 27 | Domain:domain, 28 | c:client.NewClient("8.8.8.8",53), 29 | //c:client.NewClient("114.114.114.114",53), 30 | ID:id, 31 | } 32 | } 33 | //Resolve 34 | func (e *Endpoint) Resolve() ( *[]header.DNSResource,error ) { 35 | 36 | h := header.DNS(make([]byte,12)) 37 | h.Setheader(e.ID) 38 | h.SetCount(1,0,0,0) 39 | h.SetQuestion(e.Domain,1,1) 40 | e.req = &h 41 | return e.sendQuery() 42 | } 43 | //GetResp() 44 | func (e *Endpoint) GetResp() *header.DNS{ 45 | return e.resp 46 | } 47 | //Close close 48 | func (e *Endpoint) Close(){ 49 | e.c.Close() 50 | } 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /protocol/application/dns/query.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import "github.com/brewlin/net-protocol/protocol/header" 4 | 5 | //sendQuery udp query dns 6 | func (e *Endpoint) sendQuery () ( *[]header.DNSResource ,error ) { 7 | 8 | if err := e.c.Connect();err != nil { 9 | return nil,err 10 | } 11 | if err := e.c.Write(*e.req) ; err != nil { 12 | return nil,err 13 | } 14 | return e.parseResp() 15 | } -------------------------------------------------------------------------------- /protocol/application/dns/rsp.go: -------------------------------------------------------------------------------- 1 | package dns 2 | 3 | import ( 4 | "github.com/brewlin/net-protocol/protocol/header" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | //parseResp 10 | //解析响应 11 | func (e *Endpoint) parseResp() (*[]header.DNSResource,error){ 12 | rsp,err := e.c.Read() 13 | if err != nil { 14 | return nil,err 15 | } 16 | p := header.DNS(rsp) 17 | e.resp = &p 18 | e.answer = p.GetAnswer( ) 19 | return e.parseAnswer() 20 | } 21 | 22 | func (e *Endpoint) parseAnswer()(*[]header.DNSResource,error){ 23 | for i := 0; i < len(*e.answer) ; i++ { 24 | switch (*e.answer)[i].Type { 25 | case header.A: 26 | (*e.answer)[i].Address = e.parseAName((*e.answer)[i].RData) 27 | case header.CNAME: 28 | (*e.answer)[i].Address = e.parseCName((*e.answer)[i].RData) 29 | } 30 | } 31 | return e.answer,nil 32 | } 33 | func (e *Endpoint)parseAName(rd []byte) string { 34 | res := []string{} 35 | for _,v := range rd { 36 | res = append(res,strconv.Itoa(int(v))) 37 | } 38 | return strings.Join(res,".") 39 | } 40 | 41 | func (e *Endpoint)parseCName(rd []byte) (res string) { 42 | 43 | for{ 44 | l := int(rd[0]) 45 | if l >= len(rd){ 46 | res += ".com" 47 | return 48 | } 49 | rd = rd[1:] 50 | res += string(rd[0:l]) 51 | rd = rd[l:] 52 | if len(rd) == 0 { 53 | return 54 | } 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /protocol/application/http/client.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/brewlin/net-protocol/pkg/buffer" 5 | "github.com/brewlin/net-protocol/protocol/transport/tcp/client" 6 | ) 7 | 8 | type Client struct { 9 | con *Connection 10 | client *client.Client 11 | req *Request 12 | } 13 | //NewCient new http client 14 | //NewClient("http://10.0.2.15:8080/") 15 | func NewClient(url string)(*Client,error){ 16 | ip,port,path,err := buffer.ParseUrl(url) 17 | if err != nil { 18 | return nil,err 19 | } 20 | fd := client.NewClient(ip,port) 21 | if err := fd.Connect(); err != nil { 22 | return nil,err 23 | } 24 | c := NewCon(fd) 25 | req := newRequest() 26 | req.init(path,ip,port) 27 | return &Client{ 28 | con:c, 29 | client:fd, 30 | req:req, 31 | },nil 32 | } 33 | //SetMethod 34 | func (c *Client)SetMethod(method string) { 35 | c.req.method_raw = method 36 | } 37 | //SetHeaders 38 | func (c *Client)SetHeaders(headers map[string]string){ 39 | for k,v := range headers { 40 | c.req.headers.ptr[k] = v 41 | } 42 | } 43 | //SetData 44 | func (c *Client)SetData(buf string) { 45 | c.req.body = buf 46 | } 47 | //GetResult 48 | func (c *Client)GetResult()(string,error) { 49 | if err := c.Push();err != nil { 50 | return "",err 51 | } 52 | return c.con.request.GetBody(),nil 53 | } 54 | //GetBody 55 | func (c *Client)Push()(err error) { 56 | buf := c.req.send() 57 | if err = c.client.Write([]byte(buf)); err != nil { 58 | return 59 | } 60 | recvbuf,_ := c.client.Read() 61 | c.con.recv_buf = string(recvbuf) 62 | c.con.request.parse(c.con) 63 | return 64 | } 65 | //GetConnection 66 | func (c *Client)GetConnection()*Connection{ 67 | return c.con 68 | } 69 | func (c *Client)GetRequest()*Request{ 70 | return c.con.request 71 | } -------------------------------------------------------------------------------- /protocol/application/http/connection.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/brewlin/net-protocol/internal/socket" 5 | "log" 6 | "sync" 7 | 8 | "github.com/brewlin/net-protocol/pkg/buffer" 9 | "github.com/brewlin/net-protocol/pkg/waiter" 10 | tcpip "github.com/brewlin/net-protocol/protocol" 11 | ) 12 | 13 | type Connection struct { 14 | // 客户端连接的socket 15 | socket socket.Socket 16 | // 状态码 17 | status_code int 18 | // 接收队列 19 | recv_buf string 20 | // HTTP请求 21 | request *Request 22 | // HTTP响应 23 | response *Response 24 | // 接收状态 25 | recv_state http_recv_state 26 | // 客户端地址信息 27 | addr *tcpip.FullAddress 28 | // 请求长度 29 | request_len int 30 | // 请求文件的真实路径 31 | real_path string 32 | 33 | //接受队列缓存区 34 | buf buffer.View 35 | bufmu sync.RWMutex 36 | 37 | q *waiter.Queue 38 | waitEntry waiter.Entry 39 | notifyC chan struct{} 40 | } 41 | 42 | //等待并接受新的连接 43 | func NewCon(e socket.Socket) *Connection { 44 | var con Connection 45 | //创建结构实例 46 | con.status_code = 200 47 | con.request_len = 0 48 | con.socket = e 49 | con.real_path = "" 50 | con.recv_state = HTTP_RECV_STATE_WORD1 51 | con.request = newRequest() 52 | con.response = newResponse(&con) 53 | con.recv_buf = "" 54 | log.Println("@application http: new client connection : ", *e.GetRemoteAddr()) 55 | con.addr = e.GetRemoteAddr() 56 | con.q = e.GetQueue() 57 | return &con 58 | 59 | } 60 | //Close close the connection 61 | func (con *Connection)Close() { 62 | con.socket.Close() 63 | } 64 | //Write 65 | func (con *Connection)Write(buf []byte)error{ 66 | return con.socket.Write(buf) 67 | } 68 | //Read 读取单次所有数据包 不等待直接返回 69 | func (con *Connection)Read()([]byte,error){ 70 | return con.socket.Read() 71 | } 72 | //Readn 读取n字节 73 | func (con *Connection)Readn(p []byte)(int,error){ 74 | return con.socket.Readn(p) 75 | } 76 | //HTTP 请求处理主函数 77 | //从socket中读取数据并解析http请求 78 | //解析请求 79 | //发送响应 80 | //记录请求日志 81 | func (con *Connection) handler() { 82 | log.Println("@应用层 http: waiting new event trigger ...") 83 | v,_ := con.socket.Read() 84 | con.recv_buf = string(v) 85 | log.Println("http协议原始数据:",con.recv_buf) 86 | con.request.parse(con) 87 | //dispatch the route request 88 | defaultMux.dispatch(con) 89 | con.response.send() 90 | } 91 | 92 | // 设置状态 93 | func (c *Connection) set_status_code(code int) { 94 | if c.status_code == 0 { 95 | c.status_code = code 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /protocol/application/http/define.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | // HTTP请求的方 4 | type http_method int 5 | 6 | const ( 7 | //不识别该 未知方法 8 | HTTP_METHOD_UNKNOWN http_method = -1 9 | //不支持的请求方法 10 | HTTP_METHOD_NOT_SUPPORTED http_method = 0 11 | //GET请求方法 12 | HTTP_METHOD_GET http_method = 1 13 | //HEAD请求方法 14 | HTTP_METHOD_HEAD http_method = 2 15 | ) 16 | 17 | //http 版本 18 | type http_version int 19 | 20 | const ( 21 | HTTP_VERSION_UNKNOWN http_version = iota 22 | HTTP_VERSION_09 23 | HTTP_VERSION_10 24 | HTTP_VERSION_11 25 | ) 26 | 27 | //接受状态 28 | type http_recv_state int 29 | 30 | const ( 31 | HTTP_RECV_STATE_WORD1 http_recv_state = iota 32 | HTTP_RECV_STATE_WORD2 33 | HTTP_RECV_STATE_WORD3 34 | HTTP_RECV_STATE_SP1 35 | HTTP_RECV_STATE_SP2 36 | HTTP_RECV_STATE_LF 37 | HTTP_RECV_STATE_LINE 38 | ) 39 | 40 | const default_err_msg = "ERROR

SOMETING WRONG

" 41 | const default_success_msg = "SUCCESS

github.com/brewlin/net-protocol/http

" 42 | 43 | var mime = map[string]string{ 44 | ".html": "text/html", 45 | ".css": "text/css", 46 | ".js": "application/javascript", 47 | ".jpg": "image/jpg", 48 | ".png": "image/png", 49 | } 50 | -------------------------------------------------------------------------------- /protocol/application/http/header.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | //HTTP头部,包含若干个键值对,键值对的数量和头部长度 4 | type http_headers struct { 5 | //HTTP头部中使用的键值对 6 | ptr map[string]string 7 | len int 8 | size int 9 | } 10 | 11 | func newHeaders() *http_headers { 12 | h := new(http_headers) 13 | h.ptr = make(map[string]string) 14 | h.len = 0 15 | h.size = 0 16 | return h 17 | } 18 | 19 | //添加新的key-value对到HTTP头部 20 | func (h *http_headers) http_headers_add(key, value string) { 21 | 22 | h.ptr[key] = value 23 | h.len++ 24 | } 25 | -------------------------------------------------------------------------------- /protocol/application/http/interface.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | //Socket 提供数据读写io接口 4 | type Socket interface{ 5 | //Write write 6 | Write(buf []byte) error 7 | //Read data 8 | Read() ([]byte, error) 9 | //Readn 读取固定字节的数据 10 | Readn(p []byte) (int, error) 11 | Close() 12 | 13 | } -------------------------------------------------------------------------------- /protocol/application/http/pkg.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | // 一直读取字符直到遇到delims字符串,将先前读取的返回 8 | // 可以用在解析HTTP请求时获取HTTP方法名(第一段字符串 9 | func match_until(buf, delims string) (string, string) { 10 | i := strings.Index(buf, delims) 11 | if i == -1 { 12 | return "", "" 13 | } 14 | return buf[:i], buf[i+len(delims):] 15 | } 16 | 17 | // 根据字符串获得请求中的HTTP方法,目前只支持GET和HEAD 18 | func get_method(method string) http_method { 19 | if method == "GET" { 20 | return HTTP_METHOD_GET 21 | } else if method == "HEAD" { 22 | return HTTP_METHOD_HEAD 23 | } else if method == "POST" || method == "PUT" { 24 | return HTTP_METHOD_NOT_SUPPORTED 25 | } 26 | return HTTP_METHOD_UNKNOWN 27 | } 28 | -------------------------------------------------------------------------------- /protocol/application/http/request.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "log" 5 | "strings" 6 | ) 7 | 8 | // HTTP请求结构体,包含HTTP方法,版本,URI,HTTP头,内容长 9 | type Request struct { 10 | //http 请求方法 11 | method http_method 12 | //http 版本 13 | version http_version 14 | //原始方法 15 | method_raw string 16 | //原始版本 17 | version_raw string 18 | uri string 19 | port int 20 | headers *http_headers 21 | content_length int 22 | //数据包 body 23 | body string 24 | } 25 | 26 | //初始化一个httprequest 27 | func newRequest() *Request { 28 | var req Request 29 | req.content_length = 0 30 | req.version = HTTP_VERSION_UNKNOWN 31 | req.content_length = -1 32 | req.headers = newHeaders() 33 | return &req 34 | 35 | } 36 | 37 | //解析httprequest 38 | func (req *Request) parse(con *Connection) { 39 | buf := con.recv_buf 40 | 41 | req.method_raw, buf = match_until(buf, " ") 42 | log.Println("@application http: header parse method_raw:", req.method_raw) 43 | 44 | if req.method_raw == "" { 45 | con.status_code = 400 46 | return 47 | } 48 | 49 | // 获得HTTP方法 50 | req.method = get_method(req.method_raw) 51 | log.Println("@application http: header parse method:", req.method) 52 | 53 | if req.method == HTTP_METHOD_NOT_SUPPORTED { 54 | con.set_status_code(501) 55 | } else if req.method == HTTP_METHOD_UNKNOWN { 56 | con.status_code = 400 57 | } 58 | 59 | // 获得URI 60 | req.uri, buf = match_until(buf, " ") 61 | log.Println("@application http: header parse uri:", req.uri) 62 | 63 | if req.uri == "" { 64 | con.status_code = 400 65 | } 66 | 67 | /* 68 | * 判断访问的资源是否在服务器上 69 | * 70 | */ 71 | // if (resolve_uri(con.real_path, serv.conf.doc_root, req.uri) == -1) { 72 | // try_set_status(con, 404); 73 | // } 74 | 75 | // 如果版本为HTTP_VERSION_09立刻退出 76 | if req.version == HTTP_VERSION_09 { 77 | con.set_status_code(200) 78 | req.version_raw = "" 79 | return 80 | } 81 | 82 | // 获得HTTP版本 83 | req.version_raw, buf = match_until(buf, "\r\n") 84 | log.Println("@application http: header parse version_raw:", req.version_raw) 85 | 86 | if req.version_raw == "" { 87 | con.status_code = 400 88 | return 89 | } 90 | 91 | // 支持HTTP/1.0或HTTP/1.1 92 | if strings.EqualFold(req.version_raw, "HTTP/1.0") { 93 | req.version = HTTP_VERSION_10 94 | } else if strings.EqualFold(req.version_raw, "HTTP/1.1") { 95 | req.version = HTTP_VERSION_11 96 | } else { 97 | con.set_status_code(400) 98 | } 99 | log.Println("@application http: header parse version:", req.version) 100 | log.Println("@application http: header parse status_code:", con.status_code) 101 | //if con.status_code > 0 { 102 | // return 103 | //} 104 | 105 | // 解析HTTP请求头部 106 | 107 | p := buf 108 | key, value,tmp := "", "","" 109 | for p != "" { 110 | if key, tmp = match_until(p, ": ");key != "" { 111 | p = tmp 112 | } 113 | if value, tmp = match_until(p, "\r\n");value != "" { 114 | p = tmp 115 | } 116 | if key == "" || value == "" { 117 | break 118 | } 119 | req.headers.http_headers_add(key, value) 120 | } 121 | //剩下到就是 body 122 | req.body = p 123 | } 124 | 125 | //GetMethod d 126 | func (req *Request) GetMethod() string { 127 | return req.method_raw 128 | } 129 | 130 | //GetHeader header 131 | func (req *Request) GetHeader(h string) string { 132 | if _, exist := req.headers.ptr[h]; !exist { 133 | return "" 134 | } 135 | return req.headers.ptr[h] 136 | } 137 | //GetBody get get|post data 138 | func (req *Request) GetBody()string{ 139 | return req.body 140 | } 141 | -------------------------------------------------------------------------------- /protocol/application/http/request_client.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "log" 5 | "strconv" 6 | ) 7 | 8 | func (r *Request)init(path,ip string,port int) { 9 | r.uri = path 10 | r.port = port 11 | r.headers.ptr = map[string]string{ 12 | "Host": ip+":" + strconv.Itoa(port), 13 | "User-Agent": "net-protocol/5.0", 14 | "Accept":"*/*", 15 | } 16 | } 17 | func (r *Request) send()string{ 18 | if r.method_raw == "" { 19 | r.method_raw = "GET" 20 | } 21 | // 构建发送的字符串 22 | buf := "" 23 | buf += r.method_raw + " " 24 | buf += r.uri + " " 25 | buf += "HTTP/1.1"+ "\r\n" 26 | for k, v := range r.headers.ptr { 27 | buf += k 28 | buf += ": " 29 | buf += v 30 | buf += "\r\n" 31 | } 32 | buf += "\r\n" 33 | buf += r.body 34 | log.Println("@application http:request send 构建http请求包体") 35 | log.Println(buf) 36 | return buf 37 | } -------------------------------------------------------------------------------- /protocol/application/http/response.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "log" 5 | "strconv" 6 | ) 7 | 8 | // HTTP响应结构体,包含内容长度,内容,HTTP头部 9 | type Response struct { 10 | content_length int 11 | entity_body string 12 | headers *http_headers 13 | con *Connection 14 | } 15 | 16 | func newResponse(con *Connection) *Response { 17 | var resp Response 18 | 19 | resp.headers = newHeaders() 20 | resp.entity_body = "" 21 | resp.content_length = -1 22 | resp.con = con 23 | return &resp 24 | } 25 | 26 | // 发送HTTP响应 27 | func (r *Response) send() { 28 | if r.con.request.version == HTTP_VERSION_09 { 29 | r.send_http09_response() 30 | } else { 31 | r.send_response() 32 | } 33 | } 34 | 35 | /* 36 | * HTTP_VERSION_09时,只发送响应消息内容,不包含头部 37 | */ 38 | func (r *Response) send_http09_response() { 39 | 40 | // 检查文件是否可以访问 && check_file_attrs(con, con.real_path) 41 | if r.con.status_code == 200 { 42 | // read_file(r.entity_body, con.real_path); 43 | } else { 44 | // read_err_file(serv, con, r.entity_body); 45 | } 46 | 47 | r.send_all(r.entity_body) 48 | } 49 | 50 | /* 51 | * 构建响应消息和消息头部并发送消息 52 | * 如果请求的资源无法打开则发送错误消息 53 | */ 54 | func (r *Response) send_response() { 55 | h := r.headers 56 | h.http_headers_add("Server", "github.com/brewlin/net-protocol/1.00") 57 | h.http_headers_add("Connection", "close") 58 | if r.entity_body == "" { 59 | r.entity_body = default_success_msg 60 | } 61 | 62 | if r.con.status_code != 200 { 63 | r.send_err_response() 64 | return 65 | } 66 | 67 | // if (check_file_attrs(con, con->real_path) == -1) { 68 | // send_err_response(serv, con); 69 | // return; 70 | // } 71 | 72 | // if r.method != HTTP_METHOD_HEAD { 73 | // read_file(resp->entity_body, con->real_path); 74 | // } 75 | 76 | // 构建消息头部 77 | // const char *mime = get_mime_type(con->real_path, "text/plain"); 78 | // http_headers_add(resp->headers, "Content-Type", mime); 79 | // http_headers_add_int(resp->headers, "Content-Length", resp->content_length); 80 | 81 | r.build_and_send_response() 82 | } 83 | 84 | //End send the body 85 | func (r *Response) End(buf string) { 86 | r.entity_body = buf 87 | } 88 | 89 | /* 90 | * 当出错时发送标准错误页面,页面名称类似404.html 91 | * 如果错误页面不存在则发送标准的错误消息 92 | */ 93 | func (r *Response) send_err_response() { 94 | // snprintf(err_file, sizeof(err_file), "%s/%d.html", serv->conf->doc_root, con->status_code); 95 | 96 | // 检查错误页面 97 | // if (check_file_attrs(con, err_file) == -1) { 98 | // resp->content_length = strlen(default_err_msg); 99 | // log_error(serv, "failed to open file %s", err_file); 100 | // } 101 | r.entity_body = default_err_msg 102 | 103 | // 构建消息头部 104 | r.headers.http_headers_add("Content-Type", "text/html") 105 | r.headers.http_headers_add("Content-Length", string(r.content_length)) 106 | 107 | // if con.request.method != HTTP_METHOD_HEAD { 108 | // read_err_file(serv, con, resp->entity_body); 109 | // } 110 | 111 | r.build_and_send_response() 112 | } 113 | 114 | // 构建并发送响应 115 | func (r *Response) build_and_send_response() { 116 | 117 | // 构建发送的字符串 118 | buf := "" 119 | 120 | buf += r.con.request.version_raw + " " 121 | buf += strconv.Itoa(r.con.status_code) 122 | buf += " " 123 | buf += StatusText(r.con.status_code) 124 | buf += "\r\n" 125 | for k, v := range r.headers.ptr { 126 | buf += k 127 | buf += ": " 128 | buf += v 129 | buf += "\r\n" 130 | } 131 | buf += "\r\n" 132 | buf += r.entity_body 133 | log.Println("@application http:response send 构建http响应包体") 134 | log.Println(buf) 135 | // 将字符串缓存发送到客户端 136 | r.send_all(buf) 137 | } 138 | 139 | /** 140 | * 将响应消息发送给客户端 141 | */ 142 | func (r *Response) send_all(buf string) { 143 | r.con.socket.Write([]byte(buf)) 144 | } 145 | 146 | //Error set status_code 147 | func (r *Response) Error(code int) { 148 | r.con.set_status_code(code) 149 | } 150 | 151 | //GetCon get 152 | func (r *Response) GetCon() *Connection { 153 | return r.con 154 | } 155 | -------------------------------------------------------------------------------- /protocol/application/http/server.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/brewlin/net-protocol/config" 5 | "log" 6 | "net" 7 | "strconv" 8 | "strings" 9 | 10 | "github.com/brewlin/net-protocol/protocol/link/fdbased" 11 | "github.com/brewlin/net-protocol/protocol/link/tuntap" 12 | "github.com/brewlin/net-protocol/protocol/transport/udp" 13 | 14 | "github.com/brewlin/net-protocol/pkg/waiter" 15 | "github.com/brewlin/net-protocol/protocol/network/ipv6" 16 | 17 | "github.com/brewlin/net-protocol/protocol/network/arp" 18 | "github.com/brewlin/net-protocol/protocol/network/ipv4" 19 | "github.com/brewlin/net-protocol/protocol/transport/tcp" 20 | "github.com/brewlin/net-protocol/stack" 21 | 22 | tcpip "github.com/brewlin/net-protocol/protocol" 23 | ) 24 | 25 | 26 | //Server Http 27 | type Server struct { 28 | socket tcpip.Endpoint 29 | port int 30 | addr tcpip.Address 31 | s *stack.Stack 32 | } 33 | 34 | //NewHTTP usage:", os.Args[0], " 35 | func NewHTTP(tapName, cidrName, addrName, portName string) *Server { 36 | var server Server 37 | log.Printf("@application listen:tap :%v addr :%v port :%v", tapName, addrName, portName) 38 | //解析mac地址 39 | maddr, err := net.ParseMAC(*config.Mac) 40 | if err != nil { 41 | log.Fatal(*config.Mac) 42 | } 43 | parseAddr := net.ParseIP(addrName) 44 | //解析IP地址,ipv4,或者ipv6 45 | var addr tcpip.Address 46 | var proto tcpip.NetworkProtocolNumber 47 | if parseAddr.To4() != nil { 48 | addr = tcpip.Address(net.ParseIP(addrName).To4()) 49 | proto = ipv4.ProtocolNumber 50 | } else if parseAddr.To16() != nil { 51 | addr = tcpip.Address(net.ParseIP(addrName).To16()) 52 | proto = ipv6.ProtocolNumber 53 | } else { 54 | log.Fatal("unkonw iptype") 55 | } 56 | localPort, err := strconv.Atoi(portName) 57 | if err != nil { 58 | log.Fatalf("unable to convert port") 59 | } 60 | if stack.Pstack != nil { 61 | server.s = stack.Pstack 62 | server.port = localPort 63 | server.addr = addr 64 | return &server 65 | } 66 | 67 | //虚拟网卡配置 68 | conf := &tuntap.Config{ 69 | Name: tapName, 70 | Mode: tuntap.TAP, 71 | } 72 | 73 | var fd int 74 | //新建虚拟网卡 75 | fd, err = tuntap.NewNetDev(conf) 76 | if err != nil { 77 | log.Fatal(err) 78 | } 79 | //启动网卡 80 | tuntap.SetLinkUp(tapName) 81 | //设置路由 82 | tuntap.SetRoute(tapName, cidrName) 83 | 84 | //抽象网卡层接口 85 | linkID := fdbased.New(&fdbased.Options{ 86 | FD: fd, 87 | MTU: 1500, 88 | Address: tcpip.LinkAddress(maddr), 89 | ResolutionRequired: true, 90 | }) 91 | //新建相关协议的协议栈 92 | s := stack.New([]string{ipv4.ProtocolName, arp.ProtocolName}, []string{tcp.ProtocolName, udp.ProtocolName}, stack.Options{}) 93 | //新建抽象网卡 94 | if err := s.CreateNamedNIC(1, "vnic1", linkID); err != nil { 95 | log.Fatal(err) 96 | } 97 | 98 | //在该协议栈上添加和注册相关的网络层协议 99 | if err := s.AddAddress(1, proto, addr); err != nil { 100 | log.Fatal(err) 101 | } 102 | 103 | //在该协议栈上添加和注册arp协议 104 | if err := s.AddAddress(1, arp.ProtocolNumber, arp.ProtocolAddress); err != nil { 105 | log.Fatal(err) 106 | } 107 | //添加默认路由 108 | s.SetRouteTable([]tcpip.Route{ 109 | { 110 | Destination: tcpip.Address(strings.Repeat("\x00", len(addr))), 111 | Mask: tcpip.AddressMask(strings.Repeat("\x00", len(addr))), 112 | Gateway: "", 113 | NIC: 1, 114 | }, 115 | }) 116 | server.s = s 117 | server.port = localPort 118 | server.addr = addr 119 | return &server 120 | } 121 | 122 | func (s *Server) ListenAndServ() { 123 | var wq waiter.Queue 124 | //新建一个tcp端 125 | ep, e := s.s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 126 | if e != nil { 127 | log.Fatal(e) 128 | } 129 | //绑定本地端口 130 | if err := ep.Bind(tcpip.FullAddress{0, "", uint16(s.port)}, nil); err != nil { 131 | log.Fatal("@application http:Bind failed: ", err) 132 | } 133 | //监听tcp 134 | if err := ep.Listen(10); err != nil { 135 | log.Fatal("@application http:Listen failed: ", err) 136 | } 137 | //等待连接 出现 138 | waitEntry, notifyCh := waiter.NewChannelEntry(nil) 139 | wq.EventRegister(&waitEntry, waiter.EventIn) 140 | defer wq.EventUnregister(&waitEntry) 141 | 142 | for { 143 | n, q, err := ep.Accept() 144 | if err != nil { 145 | if err == tcpip.ErrWouldBlock { 146 | log.Println("@application http:", " now waiting to new client connection ...") 147 | <-notifyCh 148 | continue 149 | } 150 | log.Println("@application http: Accept() failed: ", err) 151 | panic(err) 152 | } 153 | 154 | go s.dispatch(n, q) 155 | } 156 | } 157 | 158 | func (s *Server) dispatch(e tcpip.Endpoint, wq *waiter.Queue) { 159 | log.Println("@application http: dispatch got new request") 160 | fd := NewServerSocket(e, wq) 161 | con := NewCon(fd) 162 | con.handler() 163 | log.Println("@application http: dispatch close this request") 164 | con.socket.Close() 165 | } 166 | -------------------------------------------------------------------------------- /protocol/application/http/server_patttern.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type ServeMux struct { 8 | mu sync.RWMutex 9 | m map[string]muxEntry 10 | } 11 | 12 | type muxEntry struct { 13 | h func(*Request, *Response) 14 | pattern string 15 | } 16 | 17 | var defaultMux ServeMux 18 | 19 | //handle 20 | func (mu *ServeMux) dispatch(con *Connection) { 21 | if _, exist := defaultMux.m[con.request.uri]; !exist { 22 | con.set_status_code(400) 23 | return 24 | } 25 | defaultMux.m[con.request.uri].h(con.request, con.response) 26 | } 27 | 28 | //HandleFunc handle pattern 29 | func (s *Server) HandleFunc(pattern string, handler func(*Request, *Response)) { 30 | defaultMux.mu.Lock() 31 | defer defaultMux.mu.Unlock() 32 | 33 | if pattern == "" { 34 | panic("invalid pattern url") 35 | } 36 | if handler == nil { 37 | panic("http: nil handler") 38 | } 39 | if _, exist := defaultMux.m[pattern]; exist { 40 | panic("http: multiple registrations for " + pattern) 41 | } 42 | 43 | if defaultMux.m == nil { 44 | defaultMux.m = make(map[string]muxEntry) 45 | } 46 | e := muxEntry{h: handler, pattern: pattern} 47 | defaultMux.m[pattern] = e 48 | } 49 | -------------------------------------------------------------------------------- /protocol/application/http/server_socket.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "errors" 5 | "sync" 6 | 7 | "github.com/brewlin/net-protocol/pkg/buffer" 8 | "github.com/brewlin/net-protocol/pkg/waiter" 9 | 10 | tcpip "github.com/brewlin/net-protocol/protocol" 11 | ) 12 | 13 | type ServerSocket struct { 14 | e tcpip.Endpoint 15 | addr tcpip.FullAddress 16 | 17 | waitEntry waiter.Entry 18 | notifyC chan struct{} 19 | queue *waiter.Queue 20 | 21 | //接受队列缓存区 22 | buf buffer.View 23 | bufmu sync.RWMutex 24 | } 25 | 26 | func NewServerSocket(e tcpip.Endpoint, q *waiter.Queue) *ServerSocket { 27 | s := &ServerSocket{ 28 | e: e, 29 | } 30 | s.waitEntry, s.notifyC = waiter.NewChannelEntry(nil) 31 | q.EventRegister(&s.waitEntry, waiter.EventIn) 32 | s.addr, _ = e.GetRemoteAddress() 33 | s.queue = q 34 | return s 35 | } 36 | 37 | //Write write 38 | func (s *ServerSocket) Write(buf []byte) error { 39 | v := buffer.View(buf) 40 | s.e.Write(tcpip.SlicePayload(v), 41 | tcpip.WriteOptions{To: &s.addr}) 42 | return nil 43 | } 44 | 45 | //Read data 46 | func (s *ServerSocket) Read() ([]byte, error) { 47 | <-s.notifyC 48 | var buf []byte 49 | var err error 50 | for { 51 | v, _, e := s.e.Read(&s.addr) 52 | if e != nil { 53 | err = e 54 | break 55 | } 56 | buf = append(buf, v...) 57 | } 58 | if buf == nil { 59 | return nil, err 60 | } 61 | return buf, nil 62 | 63 | } 64 | 65 | //Readn 读取固定字节的数据 66 | func (s *ServerSocket) Readn(p []byte) (int, error) { 67 | s.bufmu.Lock() 68 | defer s.bufmu.Unlock() 69 | 70 | //获取足够长度的字节 71 | if len(p) > len(s.buf) { 72 | 73 | for { 74 | if len(p) <= len(s.buf) { 75 | break 76 | } 77 | buf, _, err := s.e.Read(s.GetRemoteAddr()) 78 | if err != nil { 79 | if err == tcpip.ErrWouldBlock { 80 | //阻塞等待数据 81 | <-s.GetNotify() 82 | continue 83 | } 84 | return 0, err 85 | } 86 | s.buf = append(s.buf, buf...) 87 | } 88 | } 89 | if len(p) > len(s.buf) { 90 | return 0, errors.New("package len is smaller than p need") 91 | } 92 | 93 | n := copy(p, s.buf) 94 | s.buf = s.buf[len(p):] 95 | return n, nil 96 | } 97 | //GetAddr 获取客户端ip地址 98 | func (s *ServerSocket)GetAddr()tcpip.Address{ 99 | return "" 100 | } 101 | //GetRemoteAddr 获取远程客户端ip地址 102 | func (s *ServerSocket)GetRemoteAddr()*tcpip.FullAddress{ 103 | return &s.addr 104 | } 105 | //GetQueue 获取接收时间队列 106 | func (s *ServerSocket)GetQueue()*waiter.Queue { 107 | return s.queue 108 | } 109 | //GetNotify 110 | func (s *ServerSocket)GetNotify()chan struct{} { 111 | return s.notifyC 112 | } 113 | //关闭连接 114 | func (s *ServerSocket) Close() { 115 | //注销接受队列 116 | s.queue.EventUnregister(&s.waitEntry) 117 | s.e.Close() 118 | 119 | } 120 | -------------------------------------------------------------------------------- /protocol/application/websocket/client.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import "C" 4 | import ( 5 | "github.com/brewlin/net-protocol/pkg/buffer" 6 | "github.com/brewlin/net-protocol/protocol/application/http" 7 | ) 8 | 9 | type Client struct { 10 | httpClient *http.Client 11 | con *Conn 12 | } 13 | //NewCient new http client 14 | //NewClient("http://10.0.2.15:8080/") 15 | func NewClient(url string)(*Client,error){ 16 | cli,err := http.NewClient(url) 17 | if err != nil { 18 | panic(err) 19 | } 20 | return &Client{ 21 | httpClient: cli, 22 | con: nil, 23 | },nil 24 | } 25 | //Upgrade http 协议升级为websocket协议 26 | //GET /path HTTP/1.1 27 | //Host: server.example.com 28 | //Upgrade: websocket 29 | //Connection: Upgrade 30 | //Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== 31 | //Origin: http://example.com 32 | //Sec-WebSocket-Protcol: chat, superchat 33 | //Sec-WebSocket-Version: 13 34 | func (c *Client)Upgrade()error{ 35 | headers := map[string]string{ 36 | "Upgrade":"websocket", 37 | "Connection":"Upgrade", 38 | "Sec-WebSocket-Key":buffer.GetRandomString(24), 39 | "Sec-WebSocket-Protcol":"chat, superchat", 40 | "Sec-WebSocket-Version":"13", 41 | } 42 | c.httpClient.SetHeaders(headers) 43 | if err := c.httpClient.Push(); err != nil { 44 | return err 45 | } 46 | //这里进行校验 websocket回复是否合法,本次实现不做校验 47 | //c.httpClient.GetRequest().GetHeader("Sec-WebSocket-Accept") == ? 48 | c.con = newConn(c.httpClient.GetConnection()) 49 | return nil 50 | } 51 | //Push push to websocket server data 52 | func (c *Client)Push(data string) error{ 53 | return c.con.SendData([]byte(data)) 54 | } 55 | //Recv recvData 56 | func (c *Client)Recv()(string,error) { 57 | data,err := c.con.ReadData() 58 | return string(data),err 59 | } 60 | func (c *Client)Close() { 61 | c.con.Close() 62 | } -------------------------------------------------------------------------------- /protocol/application/websocket/conn.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "log" 7 | 8 | "github.com/brewlin/net-protocol/protocol/application/http" 9 | ) 10 | 11 | const ( 12 | /* 13 | * 是否是最后一个数据帧 14 | * Fin Rsv1 Rsv2 Rsv3 Opcode 15 | * 1 0 0 0 0 0 0 0 => 128 16 | */ 17 | finalBit = 1 << 7 18 | 19 | /* 20 | * 是否需要掩码处理 21 | * Mask payload-len 第一位mask表示是否需要进行掩码处理 后面 22 | * 7位表示数据包长度 1.0-125 表示长度 2.126 后面需要扩展2 字节 16bit 23 | * 3.127则扩展8bit 24 | * 1 0 0 0 0 0 0 0 => 128 25 | */ 26 | maskBit = 1 << 7 27 | 28 | /* 29 | * 文本帧类型 30 | * 0 0 0 0 0 0 0 1 31 | */ 32 | TextMessage = 1 33 | /* 34 | * 关闭数据帧类型 35 | * 0 0 0 0 1 0 0 0 36 | */ 37 | CloseMessage = 8 38 | ) 39 | 40 | //websocket 连接 41 | type Conn struct { 42 | writeBuf []byte 43 | maskKey [4]byte 44 | conn *http.Connection 45 | } 46 | 47 | func newConn(conn *http.Connection) *Conn { 48 | return &Conn{conn: conn} 49 | } 50 | func (c *Conn) Close() { 51 | c.conn.Close() 52 | } 53 | 54 | //发送数据 55 | func (c *Conn) SendData(data []byte)error { 56 | length := len(data) 57 | c.writeBuf = make([]byte, 10+length) 58 | 59 | //数据开始和结束位置 60 | payloadStart := 2 61 | /** 62 | *数据帧的第一个字节,不支持且只能发送文本类型数据 63 | *finalBit 1 0 0 0 0 0 0 0 64 | * | 65 | *Text 0 0 0 0 0 0 0 1 66 | * => 1 0 0 0 0 0 0 1 67 | */ 68 | c.writeBuf[0] = byte(TextMessage) | finalBit 69 | log.Printf("1 bit:%b\n", c.writeBuf[0]) 70 | 71 | //数据帧第二个字节,服务器发送的数据不需要进行掩码处理 72 | switch { 73 | //大于2字节的长度 74 | case length >= 1<<16: //65536 75 | //c.writeBuf[1] = byte(0x00) | 127 // 127 76 | c.writeBuf[1] = byte(127) // 127 77 | //大端写入64位 78 | binary.BigEndian.PutUint64(c.writeBuf[payloadStart:], uint64(length)) 79 | //需要8byte来存储数据长度 80 | payloadStart += 8 81 | case length > 125: 82 | //c.writeBuf[1] = byte(0x00) | 126 83 | c.writeBuf[1] = byte(126) 84 | binary.BigEndian.PutUint16(c.writeBuf[payloadStart:], uint16(length)) 85 | payloadStart += 2 86 | default: 87 | //c.writeBuf[1] = byte(0x00) | byte(length) 88 | c.writeBuf[1] = byte(length) 89 | } 90 | log.Printf("2 bit:%b\n", c.writeBuf[1]) 91 | 92 | copy(c.writeBuf[payloadStart:], data[:]) 93 | return c.conn.Write(c.writeBuf[:payloadStart+length]) 94 | } 95 | 96 | //读取数据 97 | func (c *Conn) ReadData() (data []byte, err error) { 98 | var b [8]byte 99 | //读取数据帧的前两个字节 100 | if _, err := c.conn.Readn(b[:2]); err != nil { 101 | return nil, err 102 | } 103 | //开始解析第一个字节 是否还有后续数据帧 104 | final := b[0]&finalBit != 0 105 | log.Printf("read data 1 bit :%b\n", b[0]) 106 | //不支持数据分片 107 | if !final { 108 | log.Println("Recived fragemented frame,not support") 109 | return nil, errors.New("not suppeort fragmented message") 110 | } 111 | 112 | //数据帧类型 113 | /* 114 | *1 0 0 0 0 0 0 1 115 | * & 116 | *0 0 0 0 1 1 1 1 117 | *0 0 0 0 0 0 0 1 118 | * => 1 这样就可以直接获取到类型了 119 | */ 120 | frameType := int(b[0] & 0xf) 121 | //如果 关闭类型,则关闭连接 122 | if frameType == CloseMessage { 123 | c.conn.Close() 124 | log.Println("Recived closed message,connection will be closed") 125 | return nil, errors.New("recived closed message") 126 | } 127 | //只实现了文本格式的传输,编码utf-8 128 | if frameType != TextMessage { 129 | return nil, errors.New("only support text message") 130 | } 131 | //检查数据帧是否被掩码处理 132 | //maskBit => 1 0 0 0 0 0 0 0 任何与他 要么为0 要么为 128 133 | mask := b[1]&maskBit != 0 134 | //数据长度 135 | payloadLen := int64(b[1] & 0x7F) //0 1 1 1 1 1 1 1 1 127 136 | dataLen := int64(payloadLen) 137 | //根据payload length 判断数据的真实长度 138 | switch payloadLen { 139 | case 126: //扩展2字节 140 | if _, err := c.conn.Readn(b[:2]); err != nil { 141 | return nil, err 142 | } 143 | //获取扩展二字节的真实数据长度 144 | dataLen = int64(binary.BigEndian.Uint16(b[:2])) 145 | case 127: 146 | if _, err := c.conn.Readn(b[:8]); err != nil { 147 | return nil, err 148 | } 149 | dataLen = int64(binary.BigEndian.Uint64(b[:8])) 150 | } 151 | 152 | log.Printf("Read data length :%d,payload length %d", payloadLen, dataLen) 153 | //读取mask key 154 | if mask { //如果需要掩码处理的话 需要取出key 155 | //maskKey 是 4 字节 32位 156 | if _, err := c.conn.Readn(c.maskKey[:]); err != nil { 157 | return nil, err 158 | } 159 | } 160 | //读取数据内容 161 | p := make([]byte, dataLen) 162 | if _, err := c.conn.Readn(p); err != nil { 163 | return nil, err 164 | } 165 | if mask { 166 | maskBytes(c.maskKey, p) //进行解码 167 | } 168 | return p, nil 169 | } 170 | -------------------------------------------------------------------------------- /protocol/application/websocket/upgrade.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "log" 7 | 8 | "github.com/brewlin/net-protocol/protocol/application/http" 9 | ) 10 | 11 | func Upgrade(r *http.Request, w *http.Response) (c *Conn, err error) { 12 | //是否是Get方法 13 | if r.GetMethod() != "GET" { 14 | w.Error(http.StatusMethodNotAllowed) 15 | return nil, errors.New("websocket:method not GET") 16 | } 17 | //检查 Sec-WebSocket-Version 版本 18 | if values := r.GetHeader("Sec-WebSocket-Version"); values != "13" { 19 | w.Error(http.StatusBadRequest) 20 | return nil, errors.New("websocket:version != 13") 21 | } 22 | 23 | //检查Connection 和 Upgrade 24 | if values := r.GetHeader("Connection"); !tokenListContainsValue(values, "upgrade") { 25 | w.Error(http.StatusBadRequest) 26 | return nil, errors.New("websocket:could not find connection header with token 'upgrade'") 27 | } 28 | if values := r.GetHeader("Upgrade"); values != "websocket" { 29 | w.Error(http.StatusBadRequest) 30 | return nil, errors.New("websocket:could not find connection header with token 'websocket'") 31 | } 32 | 33 | //计算Sec-Websocket-Accept的值 34 | challengeKey := r.GetHeader("Sec-WebSocket-Key") 35 | if challengeKey == "" { 36 | w.Error(http.StatusBadRequest) 37 | return nil, errors.New("websocket:key missing or blank") 38 | } 39 | 40 | //接管当前tcp连接,阻止内置http接管连接 41 | con := w.GetCon() 42 | // 构造握手成功后返回的 response 43 | p := []byte{} 44 | p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...) 45 | p = append(p, computeAcceptKey(challengeKey)...) 46 | p = append(p, "\r\n\r\n"...) 47 | //返回repson 但不关闭连接 48 | if err = con.Write(p); err != nil { 49 | fmt.Println(err) 50 | fmt.Println("write p err", err) 51 | return nil, err 52 | } 53 | //升级为websocket 54 | log.Println("Upgrade http to websocket successfully") 55 | conn := newConn(con) 56 | return conn, nil 57 | } 58 | -------------------------------------------------------------------------------- /protocol/application/websocket/utils.go: -------------------------------------------------------------------------------- 1 | package websocket 2 | 3 | import ( 4 | "crypto/sha1" 5 | "encoding/base64" 6 | "strings" 7 | ) 8 | 9 | var KeyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") 10 | 11 | //握手阶段使用 加密key返回 进行握手 12 | func computeAcceptKey(challengeKey string) string { 13 | h := sha1.New() 14 | h.Write([]byte(challengeKey)) 15 | h.Write(KeyGUID) 16 | return base64.StdEncoding.EncodeToString(h.Sum(nil)) 17 | } 18 | 19 | //解码 20 | func maskBytes(key [4]byte, b []byte) { 21 | pos := 0 22 | for i := range b { 23 | b[i] ^= key[pos&3] 24 | pos++ 25 | } 26 | } 27 | 28 | // 检查http 头部字段中是否包含指定的值 29 | func tokenListContainsValue(h string, value string) bool { 30 | for _, s := range strings.Split(h, ",") { 31 | if strings.EqualFold(value, strings.TrimSpace(s)) { 32 | return true 33 | } 34 | } 35 | return false 36 | } 37 | -------------------------------------------------------------------------------- /protocol/header/arp.go: -------------------------------------------------------------------------------- 1 | package header 2 | 3 | import ( 4 | tcpip "github.com/brewlin/net-protocol/protocol" 5 | ) 6 | 7 | const ( 8 | //ARPProtocolnumber是arp协议号 为0x0806 9 | ARPProtocolNumber tcpip.NetworkProtocolNumber = 0x0806 10 | //arpsize是arp报文在ipv4网络下的长度 11 | ARPSize = 2 + 2 + 1 + 1 + 2 + 2*6 + 2*4 12 | ) 13 | 14 | //ARPop 表示ARP的操作码 1 2 3 4 15 | type ARPOp uint16 16 | 17 | //RFC 826定义的操作码 18 | 19 | const ( 20 | //arp请求 21 | ARPRequest ARPOp = 1 22 | //arp应答 23 | ARPReply ARPOp = 2 24 | ) 25 | 26 | //ARP报文的封装 27 | type ARP []byte 28 | 29 | //从报文中得到硬件类型 30 | func (a ARP) hardwareAddressSpace() uint16 { 31 | return uint16(a[0])<<8 | uint16(a[1]) 32 | } 33 | 34 | //从报文中得到协议类型 35 | func (a ARP) protocolAddressSpace() uint16 { 36 | return uint16(a[2])<<8 | uint16(a[3]) 37 | } 38 | 39 | //从报文中得到硬件地址长度 40 | func (a ARP) hardwareAddressSize() int { 41 | return int(a[4]) 42 | } 43 | 44 | //从报文中得到协议地址长度 45 | func (a ARP) protocolAddressSize() int { 46 | return int(a[5]) 47 | } 48 | 49 | //Op从报文中得到arp操作码 50 | func (a ARP) Op() ARPOp { 51 | return ARPOp(a[6])<<8 | ARPOp(a[7]) 52 | } 53 | 54 | //SetOp 设置arp操作码 55 | func (a ARP) SetOp(op ARPOp) { 56 | a[6] = uint8(op >> 8) 57 | a[7] = uint8(op) 58 | } 59 | 60 | //SetIpv4overethernet 设置ipv4网络在以太网中arp报文的硬件和协议信息 61 | func (a ARP) SetIpv4OverEthernet() { 62 | a[0], a[1] = 0, 1 63 | a[2], a[3] = 0x08, 0x00 64 | a[4] = 6 65 | a[5] = uint8(IPv4AddressSize) 66 | } 67 | 68 | //HardwareAddressSender 从报文中得到arp发送方的硬件地址 69 | func (a ARP) HardwareAddressSender() []byte { 70 | const s = 8 71 | return a[s : s+6] 72 | } 73 | 74 | //ProtocolAddressDender 从报文中得到arp发送方的协议地址,为ipv4地址 75 | func (a ARP) ProtocolAddressSender() []byte { 76 | const s = 8 + 6 77 | return a[s : s+4] 78 | } 79 | 80 | //HardwareAddressTarget从报文中得到arp目的方硬件地址 81 | func (a ARP) HardwareAddressTarget() []byte { 82 | const s = 8 + 6 + 4 83 | return a[s : s+6] 84 | } 85 | 86 | //ProtocolAddressTarget从报文中得到ar目的方的协议地址,为ipv4地址 87 | func (a ARP) ProtocolAddressTarget() []byte { 88 | const s = 8 + 6 + 4 + 6 89 | return a[s : s+4] 90 | } 91 | 92 | //Ivalid检查arp报文是否有效 93 | func (a ARP) IsValid() bool { 94 | //比arp报文的长度小,返回无效 95 | if len(a) < ARPSize { 96 | return false 97 | } 98 | const htypeEthernet = 1 99 | const macSize = 6 100 | //是否以太网,ipv4,硬件和协议长度都对 101 | return a.hardwareAddressSpace() == htypeEthernet && a.protocolAddressSpace() == uint16(IPv4ProtocolNumber) && a.hardwareAddressSize() == macSize && a.protocolAddressSize() == IPv4AddressSize 102 | } 103 | -------------------------------------------------------------------------------- /protocol/header/checksum.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package header provides the implementation of the encoding and decoding of 16 | // network protocol headers. 17 | package header 18 | 19 | import ( 20 | tcpip "github.com/brewlin/net-protocol/protocol" 21 | ) 22 | 23 | // Checksum calculates the checksum (as defined in RFC 1071) of the bytes in the 24 | // given byte array. 25 | // 校验和的计算 26 | func Checksum(buf []byte, initial uint16) uint16 { 27 | v := uint32(initial) 28 | 29 | l := len(buf) 30 | if l&1 != 0 { 31 | l-- 32 | v += uint32(buf[l]) << 8 33 | } 34 | 35 | for i := 0; i < l; i += 2 { 36 | v += (uint32(buf[i]) << 8) + uint32(buf[i+1]) 37 | } 38 | 39 | return ChecksumCombine(uint16(v), uint16(v>>16)) 40 | } 41 | 42 | // ChecksumCombine combines the two uint16 to form their checksum. This is done 43 | // by adding them and the carry. 44 | func ChecksumCombine(a, b uint16) uint16 { 45 | v := uint32(a) + uint32(b) 46 | return uint16(v + v>>16) 47 | } 48 | 49 | // PseudoHeaderChecksum calculates the pseudo-header checksum for the 50 | // given destination protocol and network address, ignoring the length 51 | // field. Pseudo-headers are needed by transport layers when calculating 52 | // their own checksum. 53 | func PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber, srcAddr tcpip.Address, dstAddr tcpip.Address) uint16 { 54 | xsum := Checksum([]byte(srcAddr), 0) 55 | xsum = Checksum([]byte(dstAddr), xsum) 56 | return Checksum([]byte{0, uint8(protocol)}, xsum) 57 | } 58 | -------------------------------------------------------------------------------- /protocol/header/eth.go: -------------------------------------------------------------------------------- 1 | package header 2 | 3 | import ( 4 | "encoding/binary" 5 | 6 | tcpip "github.com/brewlin/net-protocol/protocol" 7 | ) 8 | 9 | //以太网帧头部信息的偏移量 10 | const ( 11 | dstMAC = 0 12 | srcMAC = 6 13 | ethType = 12 14 | ) 15 | 16 | //EthernetFields 表示链路层以太网帧的头部 17 | type EthernetFields struct { 18 | //源地址 (string) 19 | SrcAddr tcpip.LinkAddress 20 | //目的地址 21 | DstAddr tcpip.LinkAddress 22 | //协议类型 23 | Type tcpip.NetworkProtocolNumber 24 | } 25 | 26 | //Ethernet 以太网数据包的封装 27 | type Ethernet []byte 28 | 29 | const ( 30 | //EthernetMinimusize 以太网帧最小的长度 31 | EtheernetMinimumsize = 14 32 | //EthernetAddressSize 以太网地址的长度 33 | EthernetAddressSize = 6 34 | ) 35 | 36 | //SourceAddress 从帧投不中得到源地址 37 | func (b Ethernet) SourceAddress() tcpip.LinkAddress { 38 | return tcpip.LinkAddress(b[srcMAC:][:EthernetAddressSize]) 39 | } 40 | 41 | //DestinationAddress 从帧 头部中得到目的地址 42 | func (b Ethernet) DestinationAddress() tcpip.LinkAddress { 43 | return tcpip.LinkAddress(b[dstMAC:][:EthernetAddressSize]) 44 | } 45 | 46 | //Type 从帧头部中得到协议类型 47 | func (b Ethernet) Type() tcpip.NetworkProtocolNumber { 48 | return tcpip.NetworkProtocolNumber(binary.BigEndian.Uint16(b[ethType:])) 49 | } 50 | 51 | //Encode 根据传入的帧头部信息编码成Ethernet二进制形式,注意Ethernet应先分配好内存 52 | func (b Ethernet) Encode(e *EthernetFields) { 53 | binary.BigEndian.PutUint16(b[ethType:], uint16(e.Type)) 54 | copy(b[srcMAC:][:EthernetAddressSize], e.SrcAddr) 55 | copy(b[dstMAC:][:EthernetAddressSize], e.DstAddr) 56 | } 57 | -------------------------------------------------------------------------------- /protocol/header/icmpv4.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package header 16 | 17 | import ( 18 | "encoding/binary" 19 | 20 | tcpip "github.com/brewlin/net-protocol/protocol" 21 | ) 22 | 23 | // ICMPv4 represents an ICMPv4 header stored in a byte array. 24 | type ICMPv4 []byte 25 | 26 | const ( 27 | // ICMPv4MinimumSize is the minimum size of a valid ICMP packet. 28 | ICMPv4MinimumSize = 4 29 | 30 | // ICMPv4EchoMinimumSize is the minimum size of a valid ICMP echo packet. 31 | ICMPv4EchoMinimumSize = 6 32 | 33 | // ICMPv4DstUnreachableMinimumSize is the minimum size of a valid ICMP 34 | // destination unreachable packet. 35 | ICMPv4DstUnreachableMinimumSize = ICMPv4MinimumSize + 4 36 | 37 | // ICMPv4ProtocolNumber is the ICMP transport protocol number. 38 | ICMPv4ProtocolNumber tcpip.TransportProtocolNumber = 1 39 | ) 40 | 41 | // ICMPv4Type is the ICMP type field described in RFC 792. 42 | type ICMPv4Type byte 43 | 44 | // Typical values of ICMPv4Type defined in RFC 792. 45 | const ( 46 | ICMPv4EchoReply ICMPv4Type = 0 47 | ICMPv4DstUnreachable ICMPv4Type = 3 48 | ICMPv4SrcQuench ICMPv4Type = 4 49 | ICMPv4Redirect ICMPv4Type = 5 50 | ICMPv4Echo ICMPv4Type = 8 51 | ICMPv4TimeExceeded ICMPv4Type = 11 52 | ICMPv4ParamProblem ICMPv4Type = 12 53 | ICMPv4Timestamp ICMPv4Type = 13 54 | ICMPv4TimestampReply ICMPv4Type = 14 55 | ICMPv4InfoRequest ICMPv4Type = 15 56 | ICMPv4InfoReply ICMPv4Type = 16 57 | ) 58 | 59 | // Values for ICMP code as defined in RFC 792. 60 | const ( 61 | ICMPv4PortUnreachable = 3 62 | ICMPv4FragmentationNeeded = 4 63 | ) 64 | 65 | // Type is the ICMP type field. 66 | func (b ICMPv4) Type() ICMPv4Type { return ICMPv4Type(b[0]) } 67 | 68 | // SetType sets the ICMP type field. 69 | func (b ICMPv4) SetType(t ICMPv4Type) { b[0] = byte(t) } 70 | 71 | // Code is the ICMP code field. Its meaning depends on the value of Type. 72 | func (b ICMPv4) Code() byte { return b[1] } 73 | 74 | // SetCode sets the ICMP code field. 75 | func (b ICMPv4) SetCode(c byte) { b[1] = c } 76 | 77 | // Checksum is the ICMP checksum field. 78 | func (b ICMPv4) Checksum() uint16 { 79 | return binary.BigEndian.Uint16(b[2:]) 80 | } 81 | 82 | // SetChecksum sets the ICMP checksum field. 83 | func (b ICMPv4) SetChecksum(checksum uint16) { 84 | binary.BigEndian.PutUint16(b[2:], checksum) 85 | } 86 | 87 | // SourcePort implements Transport.SourcePort. 88 | func (ICMPv4) SourcePort() uint16 { 89 | return 0 90 | } 91 | 92 | // DestinationPort implements Transport.DestinationPort. 93 | func (ICMPv4) DestinationPort() uint16 { 94 | return 0 95 | } 96 | 97 | // SetSourcePort implements Transport.SetSourcePort. 98 | func (ICMPv4) SetSourcePort(uint16) { 99 | } 100 | 101 | // SetDestinationPort implements Transport.SetDestinationPort. 102 | func (ICMPv4) SetDestinationPort(uint16) { 103 | } 104 | 105 | // Payload implements Transport.Payload. 106 | func (b ICMPv4) Payload() []byte { 107 | return b[ICMPv4MinimumSize:] 108 | } 109 | -------------------------------------------------------------------------------- /protocol/header/icmpv6.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package header 16 | 17 | import ( 18 | "encoding/binary" 19 | 20 | tcpip "github.com/brewlin/net-protocol/protocol" 21 | ) 22 | 23 | // ICMPv6 represents an ICMPv6 header stored in a byte array. 24 | type ICMPv6 []byte 25 | 26 | const ( 27 | // ICMPv6MinimumSize is the minimum size of a valid ICMP packet. 28 | ICMPv6MinimumSize = 4 29 | 30 | // ICMPv6ProtocolNumber is the ICMP transport protocol number. 31 | ICMPv6ProtocolNumber tcpip.TransportProtocolNumber = 58 32 | 33 | // ICMPv6NeighborSolicitMinimumSize is the minimum size of a 34 | // neighbor solicitation packet. 35 | ICMPv6NeighborSolicitMinimumSize = ICMPv6MinimumSize + 4 + 16 36 | 37 | // ICMPv6NeighborAdvertSize is size of a neighbor advertisement. 38 | ICMPv6NeighborAdvertSize = 32 39 | 40 | // ICMPv6EchoMinimumSize is the minimum size of a valid ICMP echo packet. 41 | ICMPv6EchoMinimumSize = 8 42 | 43 | // ICMPv6DstUnreachableMinimumSize is the minimum size of a valid ICMP 44 | // destination unreachable packet. 45 | ICMPv6DstUnreachableMinimumSize = ICMPv6MinimumSize + 4 46 | 47 | // ICMPv6PacketTooBigMinimumSize is the minimum size of a valid ICMP 48 | // packet-too-big packet. 49 | ICMPv6PacketTooBigMinimumSize = ICMPv6MinimumSize + 4 50 | ) 51 | 52 | // ICMPv6Type is the ICMP type field described in RFC 4443 and friends. 53 | type ICMPv6Type byte 54 | 55 | // Typical values of ICMPv6Type defined in RFC 4443. 56 | const ( 57 | ICMPv6DstUnreachable ICMPv6Type = 1 58 | ICMPv6PacketTooBig ICMPv6Type = 2 59 | ICMPv6TimeExceeded ICMPv6Type = 3 60 | ICMPv6ParamProblem ICMPv6Type = 4 61 | ICMPv6EchoRequest ICMPv6Type = 128 62 | ICMPv6EchoReply ICMPv6Type = 129 63 | 64 | // Neighbor Discovery Protocol (NDP) messages, see RFC 4861. 65 | 66 | ICMPv6RouterSolicit ICMPv6Type = 133 67 | ICMPv6RouterAdvert ICMPv6Type = 134 68 | ICMPv6NeighborSolicit ICMPv6Type = 135 69 | ICMPv6NeighborAdvert ICMPv6Type = 136 70 | ICMPv6RedirectMsg ICMPv6Type = 137 71 | ) 72 | 73 | // Values for ICMP code as defined in RFC 4443. 74 | const ( 75 | ICMPv6PortUnreachable = 4 76 | ) 77 | 78 | // Type is the ICMP type field. 79 | func (b ICMPv6) Type() ICMPv6Type { return ICMPv6Type(b[0]) } 80 | 81 | // SetType sets the ICMP type field. 82 | func (b ICMPv6) SetType(t ICMPv6Type) { b[0] = byte(t) } 83 | 84 | // Code is the ICMP code field. Its meaning depends on the value of Type. 85 | func (b ICMPv6) Code() byte { return b[1] } 86 | 87 | // SetCode sets the ICMP code field. 88 | func (b ICMPv6) SetCode(c byte) { b[1] = c } 89 | 90 | // Checksum is the ICMP checksum field. 91 | func (b ICMPv6) Checksum() uint16 { 92 | return binary.BigEndian.Uint16(b[2:]) 93 | } 94 | 95 | // SetChecksum calculates and sets the ICMP checksum field. 96 | func (b ICMPv6) SetChecksum(checksum uint16) { 97 | binary.BigEndian.PutUint16(b[2:], checksum) 98 | } 99 | 100 | // SourcePort implements Transport.SourcePort. 101 | func (ICMPv6) SourcePort() uint16 { 102 | return 0 103 | } 104 | 105 | // DestinationPort implements Transport.DestinationPort. 106 | func (ICMPv6) DestinationPort() uint16 { 107 | return 0 108 | } 109 | 110 | // SetSourcePort implements Transport.SetSourcePort. 111 | func (ICMPv6) SetSourcePort(uint16) { 112 | } 113 | 114 | // SetDestinationPort implements Transport.SetDestinationPort. 115 | func (ICMPv6) SetDestinationPort(uint16) { 116 | } 117 | 118 | // Payload implements Transport.Payload. 119 | func (b ICMPv6) Payload() []byte { 120 | return b[ICMPv6MinimumSize:] 121 | } 122 | -------------------------------------------------------------------------------- /protocol/header/interfaces.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package header 16 | 17 | import ( 18 | tcpip "github.com/brewlin/net-protocol/protocol" 19 | ) 20 | 21 | const ( 22 | // MaxIPPacketSize is the maximum supported IP packet size, excluding 23 | // jumbograms. The maximum IPv4 packet size is 64k-1 (total size must fit 24 | // in 16 bits). For IPv6, the payload max size (excluding jumbograms) is 25 | // 64k-1 (also needs to fit in 16 bits). So we use 64k - 1 + 2 * m, where 26 | // m is the minimum IPv6 header size; we leave room for some potential 27 | // IP options. 28 | MaxIPPacketSize = 0xffff + 2*IPv6MinimumSize 29 | ) 30 | 31 | // Transport offers generic methods to query and/or update the fields of the 32 | // header of a transport protocol buffer. 33 | type Transport interface { 34 | // SourcePort returns the value of the "source port" field. 35 | SourcePort() uint16 36 | 37 | // Destination returns the value of the "destination port" field. 38 | DestinationPort() uint16 39 | 40 | // Checksum returns the value of the "checksum" field. 41 | Checksum() uint16 42 | 43 | // SetSourcePort sets the value of the "source port" field. 44 | SetSourcePort(uint16) 45 | 46 | // SetDestinationPort sets the value of the "destination port" field. 47 | SetDestinationPort(uint16) 48 | 49 | // SetChecksum sets the value of the "checksum" field. 50 | SetChecksum(uint16) 51 | 52 | // Payload returns the data carried in the transport buffer. 53 | Payload() []byte 54 | } 55 | 56 | // Network offers generic methods to query and/or update the fields of the 57 | // header of a network protocol buffer. 58 | type Network interface { 59 | // SourceAddress returns the value of the "source address" field. 60 | SourceAddress() tcpip.Address 61 | 62 | // DestinationAddress returns the value of the "destination address" 63 | // field. 64 | DestinationAddress() tcpip.Address 65 | 66 | // Checksum returns the value of the "checksum" field. 67 | Checksum() uint16 68 | 69 | // SetSourceAddress sets the value of the "source address" field. 70 | SetSourceAddress(tcpip.Address) 71 | 72 | // SetDestinationAddress sets the value of the "destination address" 73 | // field. 74 | SetDestinationAddress(tcpip.Address) 75 | 76 | // SetChecksum sets the value of the "checksum" field. 77 | SetChecksum(uint16) 78 | 79 | // TransportProtocol returns the number of the transport protocol 80 | // stored in the payload. 81 | TransportProtocol() tcpip.TransportProtocolNumber 82 | 83 | // Payload returns a byte slice containing the payload of the network 84 | // packet. 85 | Payload() []byte 86 | 87 | // TOS returns the values of the "type of service" and "flow label" fields. 88 | TOS() (uint8, uint32) 89 | 90 | // SetTOS sets the values of the "type of service" and "flow label" fields. 91 | SetTOS(t uint8, l uint32) 92 | } 93 | -------------------------------------------------------------------------------- /protocol/header/udp.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package header 16 | 17 | import ( 18 | "encoding/binary" 19 | 20 | tcpip "github.com/brewlin/net-protocol/protocol" 21 | ) 22 | 23 | const ( 24 | udpSrcPort = 0 25 | udpDstPort = 2 26 | udpLength = 4 27 | udpChecksum = 6 28 | ) 29 | 30 | // UDPFields contains the fields of a UDP packet. It is used to describe the 31 | // fields of a packet that needs to be encoded. 32 | // udp 首部字段 33 | type UDPFields struct { 34 | // SrcPort is the "source port" field of a UDP packet. 35 | SrcPort uint16 36 | 37 | // DstPort is the "destination port" field of a UDP packet. 38 | DstPort uint16 39 | 40 | // Length is the "length" field of a UDP packet. 41 | Length uint16 42 | 43 | // Checksum is the "checksum" field of a UDP packet. 44 | Checksum uint16 45 | } 46 | 47 | // UDP represents a UDP header stored in a byte array. 48 | type UDP []byte 49 | 50 | const ( 51 | // UDPMinimumSize is the minimum size of a valid UDP packet. 52 | UDPMinimumSize = 8 53 | 54 | // UDPProtocolNumber is UDP's transport protocol number. 55 | UDPProtocolNumber tcpip.TransportProtocolNumber = 17 56 | ) 57 | 58 | // SourcePort returns the "source port" field of the udp header. 59 | func (b UDP) SourcePort() uint16 { 60 | return binary.BigEndian.Uint16(b[udpSrcPort:]) 61 | } 62 | 63 | // DestinationPort returns the "destination port" field of the udp header. 64 | func (b UDP) DestinationPort() uint16 { 65 | return binary.BigEndian.Uint16(b[udpDstPort:]) 66 | } 67 | 68 | // Length returns the "length" field of the udp header. 69 | func (b UDP) Length() uint16 { 70 | return binary.BigEndian.Uint16(b[udpLength:]) 71 | } 72 | 73 | // Payload returns the data contained in the UDP datagram. 74 | func (b UDP) Payload() []byte { 75 | return b[UDPMinimumSize:] 76 | } 77 | 78 | // Checksum returns the "checksum" field of the udp header. 79 | func (b UDP) Checksum() uint16 { 80 | return binary.BigEndian.Uint16(b[udpChecksum:]) 81 | } 82 | 83 | // SetSourcePort sets the "source port" field of the udp header. 84 | func (b UDP) SetSourcePort(port uint16) { 85 | binary.BigEndian.PutUint16(b[udpSrcPort:], port) 86 | } 87 | 88 | // SetDestinationPort sets the "destination port" field of the udp header. 89 | func (b UDP) SetDestinationPort(port uint16) { 90 | binary.BigEndian.PutUint16(b[udpDstPort:], port) 91 | } 92 | 93 | // SetChecksum sets the "checksum" field of the udp header. 94 | func (b UDP) SetChecksum(checksum uint16) { 95 | binary.BigEndian.PutUint16(b[udpChecksum:], checksum) 96 | } 97 | 98 | // CalculateChecksum calculates the checksum of the udp packet, given the total 99 | // length of the packet and the checksum of the network-layer pseudo-header 100 | // (excluding the total length) and the checksum of the payload. 101 | func (b UDP) CalculateChecksum(partialChecksum uint16, totalLen uint16) uint16 { 102 | // Add the length portion of the checksum to the pseudo-checksum. 103 | tmp := make([]byte, 2) 104 | binary.BigEndian.PutUint16(tmp, totalLen) 105 | checksum := Checksum(tmp, partialChecksum) 106 | 107 | // Calculate the rest of the checksum. 108 | return Checksum(b[:UDPMinimumSize], checksum) 109 | } 110 | 111 | // Encode encodes all the fields of the udp header. 112 | func (b UDP) Encode(u *UDPFields) { 113 | binary.BigEndian.PutUint16(b[udpSrcPort:], u.SrcPort) 114 | binary.BigEndian.PutUint16(b[udpDstPort:], u.DstPort) 115 | binary.BigEndian.PutUint16(b[udpLength:], u.Length) 116 | binary.BigEndian.PutUint16(b[udpChecksum:], u.Checksum) 117 | } 118 | -------------------------------------------------------------------------------- /protocol/link/channel/channel.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package channel provides the implemention of channel-based data-link layer 16 | // endpoints. Such endpoints allow injection of inbound packets and store 17 | // outbound packets in a channel. 18 | package channel 19 | 20 | import ( 21 | tcpip "github.com/brewlin/net-protocol/protocol" 22 | "github.com/brewlin/net-protocol/pkg/buffer" 23 | "github.com/brewlin/net-protocol/stack" 24 | ) 25 | 26 | // PacketInfo holds all the information about an outbound packet. 27 | type PacketInfo struct { 28 | Header buffer.View 29 | Payload buffer.View 30 | Proto tcpip.NetworkProtocolNumber 31 | } 32 | 33 | // Endpoint is link layer endpoint that stores outbound packets in a channel 34 | // and allows injection of inbound packets. 35 | type Endpoint struct { 36 | dispatcher stack.NetworkDispatcher 37 | mtu uint32 38 | linkAddr tcpip.LinkAddress 39 | 40 | // C is where outbound packets are queued. 41 | C chan PacketInfo 42 | } 43 | 44 | // New creates a new channel endpoint. 45 | func New(size int, mtu uint32, linkAddr tcpip.LinkAddress) (tcpip.LinkEndpointID, *Endpoint) { 46 | e := &Endpoint{ 47 | C: make(chan PacketInfo, size), 48 | mtu: mtu, 49 | linkAddr: linkAddr, 50 | } 51 | 52 | return stack.RegisterLinkEndpoint(e), e 53 | } 54 | 55 | // Drain removes all outbound packets from the channel and counts them. 56 | func (e *Endpoint) Drain() int { 57 | c := 0 58 | for { 59 | select { 60 | case <-e.C: 61 | c++ 62 | default: 63 | return c 64 | } 65 | } 66 | } 67 | 68 | // Inject injects an inbound packet. 69 | func (e *Endpoint) Inject(protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) { 70 | e.InjectLinkAddr(protocol, "", vv) 71 | } 72 | 73 | // InjectLinkAddr injects an inbound packet with a remote link address. 74 | func (e *Endpoint) InjectLinkAddr(protocol tcpip.NetworkProtocolNumber, remoteLinkAddr tcpip.LinkAddress, vv buffer.VectorisedView) { 75 | e.dispatcher.DeliverNetworkPacket(e, remoteLinkAddr, "" /* localLinkAddr */, protocol, vv.Clone(nil)) 76 | } 77 | 78 | // Attach saves the stack network-layer dispatcher for use later when packets 79 | // are injected. 80 | func (e *Endpoint) Attach(dispatcher stack.NetworkDispatcher) { 81 | e.dispatcher = dispatcher 82 | } 83 | 84 | // IsAttached implements stack.LinkEndpoint.IsAttached. 85 | func (e *Endpoint) IsAttached() bool { 86 | return e.dispatcher != nil 87 | } 88 | 89 | // MTU implements stack.LinkEndpoint.MTU. It returns the value initialized 90 | // during construction. 91 | func (e *Endpoint) MTU() uint32 { 92 | return e.mtu 93 | } 94 | 95 | // Capabilities implements stack.LinkEndpoint.Capabilities. 96 | func (*Endpoint) Capabilities() stack.LinkEndpointCapabilities { 97 | return 0 98 | } 99 | 100 | // MaxHeaderLength returns the maximum size of the link layer header. Given it 101 | // doesn't have a header, it just returns 0. 102 | func (*Endpoint) MaxHeaderLength() uint16 { 103 | return 0 104 | } 105 | 106 | // LinkAddress returns the link address of this endpoint. 107 | func (e *Endpoint) LinkAddress() tcpip.LinkAddress { 108 | return e.linkAddr 109 | } 110 | 111 | // WritePacket stores outbound packets into the channel. 112 | func (e *Endpoint) WritePacket(_ *stack.Route, hdr buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) *tcpip.Error { 113 | p := PacketInfo{ 114 | Header: hdr.View(), 115 | Proto: protocol, 116 | Payload: payload.ToView(), 117 | } 118 | 119 | select { 120 | case e.C <- p: 121 | default: 122 | } 123 | 124 | return nil 125 | } 126 | -------------------------------------------------------------------------------- /protocol/link/loopback/loopback.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package loopback provides the implemention of loopback data-link layer 16 | // endpoints. Such endpoints just turn outbound packets into inbound ones. 17 | // 18 | // Loopback endpoints can be used in the networking stack by calling New() to 19 | // create a new endpoint, and then passing it as an argument to 20 | // Stack.CreateNIC(). 21 | package loopback 22 | 23 | import ( 24 | "log" 25 | 26 | "github.com/brewlin/net-protocol/pkg/buffer" 27 | tcpip "github.com/brewlin/net-protocol/protocol" 28 | "github.com/brewlin/net-protocol/stack" 29 | ) 30 | 31 | type endpoint struct { 32 | dispatcher stack.NetworkDispatcher 33 | } 34 | 35 | // New creates a new loopback endpoint. This link-layer endpoint just turns 36 | // outbound packets into inbound packets. 37 | func New() tcpip.LinkEndpointID { 38 | return stack.RegisterLinkEndpoint(&endpoint{}) 39 | } 40 | 41 | // Attach implements stack.LinkEndpoint.Attach. It just saves the stack network- 42 | // layer dispatcher for later use when packets need to be dispatched. 43 | func (e *endpoint) Attach(dispatcher stack.NetworkDispatcher) { 44 | e.dispatcher = dispatcher 45 | } 46 | 47 | // IsAttached implements stack.LinkEndpoint.IsAttached. 48 | func (e *endpoint) IsAttached() bool { 49 | return e.dispatcher != nil 50 | } 51 | 52 | // MTU implements stack.LinkEndpoint.MTU. It returns a constant that matches the 53 | // linux loopback interface. 54 | func (*endpoint) MTU() uint32 { 55 | return 65536 56 | } 57 | 58 | // Capabilities implements stack.LinkEndpoint.Capabilities. Loopback advertises 59 | // itself as supporting checksum offload, but in reality it's just omitted. 60 | func (*endpoint) Capabilities() stack.LinkEndpointCapabilities { 61 | return stack.CapabilityChecksumOffload | stack.CapabilitySaveRestore | stack.CapabilityLoopback 62 | } 63 | 64 | // MaxHeaderLength implements stack.LinkEndpoint.MaxHeaderLength. Given that the 65 | // loopback interface doesn't have a header, it just returns 0. 66 | func (*endpoint) MaxHeaderLength() uint16 { 67 | return 0 68 | } 69 | 70 | // LinkAddress returns the link address of this endpoint. 71 | func (*endpoint) LinkAddress() tcpip.LinkAddress { 72 | return "" 73 | } 74 | 75 | // WritePacket implements stack.LinkEndpoint.WritePacket. It delivers outbound 76 | // packets to the network-layer dispatcher. 77 | func (e *endpoint) WritePacket(_ *stack.Route, hdr buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) *tcpip.Error { 78 | log.Println("@链路层 loopback: 写入网卡数据 ", hdr.View) 79 | views := make([]buffer.View, 1, 1+len(payload.Views())) 80 | views[0] = hdr.View() 81 | views = append(views, payload.Views()...) 82 | vv := buffer.NewVectorisedView(len(views[0])+payload.Size(), views) 83 | 84 | // Because we're immediately turning around and writing the packet back to the 85 | // rx path, we intentionally don't preserve the remote and local link 86 | // addresses from the stack.Route we're passed. 87 | e.dispatcher.DeliverNetworkPacket(e, "" /* remoteLinkAddr */, "" /* localLinkAddr */, protocol, vv) 88 | 89 | return nil 90 | } 91 | -------------------------------------------------------------------------------- /protocol/link/rawfile/blockingpoll_unsafe.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build linux 16 | 17 | package rawfile 18 | 19 | import ( 20 | "syscall" 21 | "unsafe" 22 | ) 23 | 24 | func blockingPoll(fds *pollEvent, nfds int, timeout int64) (int, syscall.Errno) { 25 | n, _, e := syscall.Syscall(syscall.SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) 26 | return int(n), e 27 | } 28 | -------------------------------------------------------------------------------- /protocol/link/rawfile/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build linux 16 | 17 | package rawfile 18 | 19 | import ( 20 | "fmt" 21 | "syscall" 22 | 23 | tcpip "github.com/brewlin/net-protocol/protocol" 24 | ) 25 | 26 | const maxErrno = 134 27 | 28 | var translations [maxErrno]*tcpip.Error 29 | 30 | // TranslateErrno translate an errno from the syscall package into a 31 | // *tcpip.Error. 32 | // 33 | // Valid, but unreconigized errnos will be translated to 34 | // tcpip.ErrInvalidEndpointState (EINVAL). Panics on invalid errnos. 35 | func TranslateErrno(e syscall.Errno) *tcpip.Error { 36 | if err := translations[e]; err != nil { 37 | return err 38 | } 39 | return tcpip.ErrInvalidEndpointState 40 | } 41 | 42 | func addTranslation(host syscall.Errno, trans *tcpip.Error) { 43 | if translations[host] != nil { 44 | panic(fmt.Sprintf("duplicate translation for host errno %q (%d)", host.Error(), host)) 45 | } 46 | translations[host] = trans 47 | } 48 | 49 | func init() { 50 | addTranslation(syscall.EEXIST, tcpip.ErrDuplicateAddress) 51 | addTranslation(syscall.ENETUNREACH, tcpip.ErrNoRoute) 52 | addTranslation(syscall.EINVAL, tcpip.ErrInvalidEndpointState) 53 | addTranslation(syscall.EALREADY, tcpip.ErrAlreadyConnecting) 54 | addTranslation(syscall.EISCONN, tcpip.ErrAlreadyConnected) 55 | addTranslation(syscall.EADDRINUSE, tcpip.ErrPortInUse) 56 | addTranslation(syscall.EADDRNOTAVAIL, tcpip.ErrBadLocalAddress) 57 | addTranslation(syscall.EPIPE, tcpip.ErrClosedForSend) 58 | addTranslation(syscall.EWOULDBLOCK, tcpip.ErrWouldBlock) 59 | addTranslation(syscall.ECONNREFUSED, tcpip.ErrConnectionRefused) 60 | addTranslation(syscall.ETIMEDOUT, tcpip.ErrTimeout) 61 | addTranslation(syscall.EINPROGRESS, tcpip.ErrConnectStarted) 62 | addTranslation(syscall.EDESTADDRREQ, tcpip.ErrDestinationRequired) 63 | addTranslation(syscall.ENOTSUP, tcpip.ErrNotSupported) 64 | addTranslation(syscall.ENOTTY, tcpip.ErrQueueSizeNotSupported) 65 | addTranslation(syscall.ENOTCONN, tcpip.ErrNotConnected) 66 | addTranslation(syscall.ECONNRESET, tcpip.ErrConnectionReset) 67 | addTranslation(syscall.ECONNABORTED, tcpip.ErrConnectionAborted) 68 | addTranslation(syscall.EMSGSIZE, tcpip.ErrMessageTooLong) 69 | addTranslation(syscall.ENOBUFS, tcpip.ErrNoBufferSpace) 70 | } 71 | -------------------------------------------------------------------------------- /protocol/link/rawfile/rawfile_unsafe.go: -------------------------------------------------------------------------------- 1 | package rawfile 2 | 3 | // Copyright 2018 Google LLC 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // +build linux 18 | 19 | // Package rawfile contains utilities for using the github.com/brewlin/net-protocol with raw host 20 | // files on Linux hosts. 21 | 22 | import ( 23 | "syscall" 24 | "unsafe" 25 | 26 | tcpip "github.com/brewlin/net-protocol/protocol" 27 | ) 28 | 29 | // GetMTU determines the MTU of a network interface device. 30 | func GetMTU(name string) (uint32, error) { 31 | fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0) 32 | if err != nil { 33 | return 0, err 34 | } 35 | 36 | defer syscall.Close(fd) 37 | 38 | var ifreq struct { 39 | name [16]byte 40 | mtu int32 41 | _ [20]byte 42 | } 43 | 44 | copy(ifreq.name[:], name) 45 | _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCGIFMTU, uintptr(unsafe.Pointer(&ifreq))) 46 | if errno != 0 { 47 | return 0, errno 48 | } 49 | 50 | return uint32(ifreq.mtu), nil 51 | } 52 | 53 | // NonBlockingWrite writes the given buffer to a file descriptor. It fails if 54 | // partial data is written. 55 | func NonBlockingWrite(fd int, buf []byte) *tcpip.Error { 56 | var ptr unsafe.Pointer 57 | if len(buf) > 0 { 58 | ptr = unsafe.Pointer(&buf[0]) 59 | } 60 | 61 | _, _, e := syscall.RawSyscall(syscall.SYS_WRITE, uintptr(fd), uintptr(ptr), uintptr(len(buf))) 62 | if e != 0 { 63 | return TranslateErrno(e) 64 | } 65 | 66 | return nil 67 | } 68 | 69 | // NonBlockingWrite2 writes up to two byte slices to a file descriptor in a 70 | // single syscall. It fails if partial data is written. 71 | func NonBlockingWrite2(fd int, b1, b2 []byte) *tcpip.Error { 72 | // If the is no second buffer, issue a regular write. 73 | if len(b2) == 0 { 74 | return NonBlockingWrite(fd, b1) 75 | } 76 | 77 | // We have two buffers. Build the iovec that represents them and issue 78 | // a writev syscall. 79 | iovec := [...]syscall.Iovec{ 80 | { 81 | Base: &b1[0], 82 | Len: uint64(len(b1)), 83 | }, 84 | { 85 | Base: &b2[0], 86 | Len: uint64(len(b2)), 87 | }, 88 | } 89 | 90 | _, _, e := syscall.RawSyscall(syscall.SYS_WRITEV, uintptr(fd), uintptr(unsafe.Pointer(&iovec[0])), uintptr(len(iovec))) 91 | if e != 0 { 92 | return TranslateErrno(e) 93 | } 94 | 95 | return nil 96 | } 97 | 98 | type pollEvent struct { 99 | fd int32 100 | events int16 101 | revents int16 102 | } 103 | 104 | // BlockingRead reads from a file descriptor that is set up as non-blocking. If 105 | // no data is available, it will block in a poll() syscall until the file 106 | // descirptor becomes readable. 107 | func BlockingRead(fd int, b []byte) (int, *tcpip.Error) { 108 | for { 109 | n, _, e := syscall.RawSyscall(syscall.SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))) 110 | if e == 0 { 111 | return int(n), nil 112 | } 113 | 114 | event := pollEvent{ 115 | fd: int32(fd), 116 | events: 1, // POLLIN 117 | } 118 | 119 | _, e = blockingPoll(&event, 1, -1) 120 | if e != 0 && e != syscall.EINTR { 121 | return 0, TranslateErrno(e) 122 | } 123 | } 124 | } 125 | 126 | // BlockingReadv reads from a file descriptor that is set up as non-blocking and 127 | // stores the data in a list of iovecs buffers. If no data is available, it will 128 | // block in a poll() syscall until the file descirptor becomes readable. 129 | func BlockingReadv(fd int, iovecs []syscall.Iovec) (int, *tcpip.Error) { 130 | for { 131 | n, _, e := syscall.RawSyscall(syscall.SYS_READV, uintptr(fd), uintptr(unsafe.Pointer(&iovecs[0])), uintptr(len(iovecs))) 132 | if e == 0 { 133 | return int(n), nil 134 | } 135 | 136 | event := pollEvent{ 137 | fd: int32(fd), 138 | events: 1, // POLLIN 139 | } 140 | 141 | _, e = blockingPoll(&event, 1, -1) 142 | if e != 0 && e != syscall.EINTR { 143 | return 0, TranslateErrno(e) 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /protocol/link/sniffer/pcap.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package sniffer 16 | 17 | import "time" 18 | 19 | type pcapHeader struct { 20 | // MagicNumber is the file magic number. 21 | MagicNumber uint32 22 | 23 | // VersionMajor is the major version number. 24 | VersionMajor uint16 25 | 26 | // VersionMinor is the minor version number. 27 | VersionMinor uint16 28 | 29 | // Thiszone is the GMT to local correction. 30 | Thiszone int32 31 | 32 | // Sigfigs is the accuracy of timestamps. 33 | Sigfigs uint32 34 | 35 | // Snaplen is the max length of captured packets, in octets. 36 | Snaplen uint32 37 | 38 | // Network is the data link type. 39 | Network uint32 40 | } 41 | 42 | const pcapPacketHeaderLen = 16 43 | 44 | type pcapPacketHeader struct { 45 | // Seconds is the timestamp seconds. 46 | Seconds uint32 47 | 48 | // Microseconds is the timestamp microseconds. 49 | Microseconds uint32 50 | 51 | // IncludedLength is the number of octets of packet saved in file. 52 | IncludedLength uint32 53 | 54 | // OriginalLength is the actual length of packet. 55 | OriginalLength uint32 56 | } 57 | 58 | func newPCAPPacketHeader(incLen, orgLen uint32) pcapPacketHeader { 59 | now := time.Now() 60 | return pcapPacketHeader{ 61 | Seconds: uint32(now.Unix()), 62 | Microseconds: uint32(now.Nanosecond() / 1000), 63 | IncludedLength: incLen, 64 | OriginalLength: orgLen, 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /protocol/link/tuntap/tuntap.go: -------------------------------------------------------------------------------- 1 | package tuntap 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os/exec" 7 | "syscall" 8 | "unsafe" 9 | ) 10 | 11 | const ( 12 | TUN = 1 13 | TAP = 2 14 | ) 15 | 16 | var ( 17 | ErrDeviceMode = errors.New("unsupport device mode") 18 | ) 19 | 20 | type rawSockaddr struct { 21 | Family uint16 22 | Data [14]byte 23 | } 24 | 25 | //创建虚拟网卡 26 | type Config struct { 27 | Name string //网卡名 28 | Mode int //网卡模式 TUN OR TAP 29 | } 30 | 31 | //NewNetDev 根据配置返回虚拟网卡的文件描述符 32 | func NewNetDev(c *Config) (fd int, err error) { 33 | switch c.Mode { 34 | case TUN: 35 | fd, err = newTun(c.Name) 36 | case TAP: 37 | fd, err = newTap(c.Name) 38 | default: 39 | err = ErrDeviceMode 40 | return 41 | } 42 | if err != nil { 43 | return 44 | } 45 | return 46 | } 47 | 48 | //CreateTap 通过命令行 ip 创建网卡 49 | func CreateTap(name string) (err error) { 50 | //ip tuntap add mode tap tap0 51 | out, cmdErr := exec.Command("ip", "tuntap", "add", "mode", "tap", name).CombinedOutput() 52 | if cmdErr != nil { 53 | err = fmt.Errorf("%v:%v", cmdErr, string(out)) 54 | return 55 | } 56 | return 57 | } 58 | 59 | //SetLinkUp 让系统启动该网卡 60 | func SetLinkUp(name string) (err error) { 61 | //ip link set up 62 | out, cmdErr := exec.Command("ip", "link", "set", name, "up").CombinedOutput() 63 | if cmdErr != nil { 64 | err = fmt.Errorf("%v:%v", cmdErr, string(out)) 65 | return 66 | } 67 | return 68 | } 69 | 70 | //SetRoute 通过ip命令添加路由 71 | func SetRoute(name, cidr string) (err error) { 72 | //ip route add 192.168.1.0/24 dev tap0 73 | out, cmdErr := exec.Command("ip", "route", "add", cidr, "dev", name).CombinedOutput() 74 | if cmdErr != nil { 75 | err = fmt.Errorf("%v:%v", cmdErr, string(out)) 76 | return 77 | } 78 | return 79 | } 80 | 81 | //AddIP 通过ip命令添加ip地址 82 | func AddIP(name, ip string) (err error) { 83 | //ip addr add 192.168.1.1 dev tap0 84 | out, cmdErr := exec.Command("ip", "addr", "add", ip, "dev", name).CombinedOutput() 85 | if cmdErr != nil { 86 | err = fmt.Errorf("%v:%v", cmdErr, string(out)) 87 | return 88 | } 89 | return 90 | } 91 | 92 | //AddGateWay 通过ip命令 添加网关 93 | func AddGateWay(dst, gateway, name string) (err error) { 94 | //ip route add default via gateway dev tap 95 | out, cmdErr := exec.Command("ip", "route", "add", dst, "via", gateway, "dev", name).CombinedOutput() 96 | if cmdErr != nil { 97 | err = fmt.Errorf("%v:%v", cmdErr, string(out)) 98 | return 99 | } 100 | return 101 | } 102 | 103 | //DelTap 删除网卡 104 | func DelTap(name string) (err error) { 105 | out, cmdErr := exec.Command("ip", "tuntap", "del", "mode", "tap", name).CombinedOutput() 106 | if cmdErr != nil { 107 | err = fmt.Errorf("%v:%v", cmdErr, string(out)) 108 | return 109 | } 110 | return 111 | } 112 | 113 | //GetHardwareAddr gethard 114 | func GetHardwareAddr(name string) (string, error) { 115 | fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0) 116 | if err != nil { 117 | return "", err 118 | } 119 | defer syscall.Close(fd) 120 | 121 | var ifreq struct { 122 | name [16]byte 123 | addr rawSockaddr 124 | _ [8]byte 125 | } 126 | copy(ifreq.name[:], name) 127 | _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCGIFHWADDR, uintptr(unsafe.Pointer(&ifreq))) 128 | if errno != 0 { 129 | return "", errno 130 | } 131 | mac := ifreq.addr.Data[:6] 132 | return string(mac[:]), nil 133 | } 134 | 135 | //newTun 新建一个tun模式的虚拟网卡,然后返回该网卡的文件描述符 IFF_NO_PI表示不需要包信息 136 | func newTun(name string) (int, error) { 137 | return open(name, syscall.IFF_TUN|syscall.IFF_NO_PI) 138 | } 139 | 140 | //newTAP 新建一个tap模式的虚拟网卡,然后返回该网卡的文件描述符 141 | func newTap(name string) (int, error) { 142 | return open(name, syscall.IFF_TAP|syscall.IFF_NO_PI) 143 | } 144 | 145 | //先打开一个字符串设备,通过系统调用将虚拟网卡和字符串设备fd绑定在一起 146 | func open(name string, flags uint16) (int, error) { 147 | //打开tuntap的字符设备,得到字符设备的文件描述符 148 | fd, err := syscall.Open("/dev/net/tun", syscall.O_RDWR, 0) 149 | if err != nil { 150 | return -1, err 151 | } 152 | 153 | var ifr struct { 154 | name [16]byte 155 | flags uint16 156 | _ [22]byte 157 | } 158 | copy(ifr.name[:], name) 159 | ifr.flags = flags 160 | //通过ioctl系统调用,将fd和虚拟网卡驱动绑定在一起 161 | _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.TUNSETIFF, uintptr(unsafe.Pointer(&ifr))) 162 | if errno != 0 { 163 | syscall.Close(fd) 164 | return -1, errno 165 | } 166 | return fd, nil 167 | } 168 | -------------------------------------------------------------------------------- /protocol/network/fragmentation/frag_heap.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package fragmentation 16 | 17 | import ( 18 | "container/heap" 19 | "fmt" 20 | 21 | "github.com/brewlin/net-protocol/pkg/buffer" 22 | ) 23 | 24 | type fragment struct { 25 | offset uint16 26 | vv buffer.VectorisedView 27 | } 28 | 29 | type fragHeap []fragment 30 | 31 | func (h *fragHeap) Len() int { 32 | return len(*h) 33 | } 34 | 35 | func (h *fragHeap) Less(i, j int) bool { 36 | return (*h)[i].offset < (*h)[j].offset 37 | } 38 | 39 | func (h *fragHeap) Swap(i, j int) { 40 | (*h)[i], (*h)[j] = (*h)[j], (*h)[i] 41 | } 42 | 43 | func (h *fragHeap) Push(x interface{}) { 44 | *h = append(*h, x.(fragment)) 45 | } 46 | 47 | func (h *fragHeap) Pop() interface{} { 48 | old := *h 49 | n := len(old) 50 | x := old[n-1] 51 | *h = old[:n-1] 52 | return x 53 | } 54 | 55 | // reassamble empties the heap and returns a VectorisedView 56 | // containing a reassambled version of the fragments inside the heap. 57 | func (h *fragHeap) reassemble() (buffer.VectorisedView, error) { 58 | curr := heap.Pop(h).(fragment) 59 | views := curr.vv.Views() 60 | size := curr.vv.Size() 61 | 62 | if curr.offset != 0 { 63 | return buffer.VectorisedView{}, fmt.Errorf("offset of the first packet is != 0 (%d)", curr.offset) 64 | } 65 | 66 | for h.Len() > 0 { 67 | curr := heap.Pop(h).(fragment) 68 | if int(curr.offset) < size { 69 | curr.vv.TrimFront(size - int(curr.offset)) 70 | } else if int(curr.offset) > size { 71 | return buffer.VectorisedView{}, fmt.Errorf("packet has a hole, expected offset %d, got %d", size, curr.offset) 72 | } 73 | size += curr.vv.Size() 74 | views = append(views, curr.vv.Views()...) 75 | } 76 | return buffer.NewVectorisedView(size, views), nil 77 | } 78 | -------------------------------------------------------------------------------- /protocol/network/fragmentation/frag_heap_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package fragmentation 16 | 17 | import ( 18 | "container/heap" 19 | "reflect" 20 | "testing" 21 | 22 | "github.com/brewlin/net-protocol/pkg/buffer" 23 | ) 24 | 25 | var reassambleTestCases = []struct { 26 | comment string 27 | in []fragment 28 | want buffer.VectorisedView 29 | }{ 30 | { 31 | comment: "Non-overlapping in-order", 32 | in: []fragment{ 33 | {offset: 0, vv: vv(1, "0")}, 34 | {offset: 1, vv: vv(1, "1")}, 35 | }, 36 | want: vv(2, "0", "1"), 37 | }, 38 | { 39 | comment: "Non-overlapping out-of-order", 40 | in: []fragment{ 41 | {offset: 1, vv: vv(1, "1")}, 42 | {offset: 0, vv: vv(1, "0")}, 43 | }, 44 | want: vv(2, "0", "1"), 45 | }, 46 | { 47 | comment: "Duplicated packets", 48 | in: []fragment{ 49 | {offset: 0, vv: vv(1, "0")}, 50 | {offset: 0, vv: vv(1, "0")}, 51 | }, 52 | want: vv(1, "0"), 53 | }, 54 | { 55 | comment: "Overlapping in-order", 56 | in: []fragment{ 57 | {offset: 0, vv: vv(2, "01")}, 58 | {offset: 1, vv: vv(2, "12")}, 59 | }, 60 | want: vv(3, "01", "2"), 61 | }, 62 | { 63 | comment: "Overlapping out-of-order", 64 | in: []fragment{ 65 | {offset: 1, vv: vv(2, "12")}, 66 | {offset: 0, vv: vv(2, "01")}, 67 | }, 68 | want: vv(3, "01", "2"), 69 | }, 70 | { 71 | comment: "Overlapping subset in-order", 72 | in: []fragment{ 73 | {offset: 0, vv: vv(3, "012")}, 74 | {offset: 1, vv: vv(1, "1")}, 75 | }, 76 | want: vv(3, "012"), 77 | }, 78 | { 79 | comment: "Overlapping subset out-of-order", 80 | in: []fragment{ 81 | {offset: 1, vv: vv(1, "1")}, 82 | {offset: 0, vv: vv(3, "012")}, 83 | }, 84 | want: vv(3, "012"), 85 | }, 86 | } 87 | 88 | func TestReassamble(t *testing.T) { 89 | for _, c := range reassambleTestCases { 90 | t.Run(c.comment, func(t *testing.T) { 91 | h := make(fragHeap, 0, 8) 92 | heap.Init(&h) 93 | for _, f := range c.in { 94 | heap.Push(&h, f) 95 | } 96 | got, err := h.reassemble() 97 | if err != nil { 98 | t.Fatal(err) 99 | } 100 | if !reflect.DeepEqual(got, c.want) { 101 | t.Errorf("got reassemble(%+v) = %v, want = %v", c.in, got, c.want) 102 | } 103 | }) 104 | } 105 | } 106 | 107 | func TestReassambleFailsForNonZeroOffset(t *testing.T) { 108 | h := make(fragHeap, 0, 8) 109 | heap.Init(&h) 110 | heap.Push(&h, fragment{offset: 1, vv: vv(1, "0")}) 111 | _, err := h.reassemble() 112 | if err == nil { 113 | t.Errorf("reassemble() did not fail when the first packet had offset != 0") 114 | } 115 | } 116 | 117 | func TestReassambleFailsForHoles(t *testing.T) { 118 | h := make(fragHeap, 0, 8) 119 | heap.Init(&h) 120 | heap.Push(&h, fragment{offset: 0, vv: vv(1, "0")}) 121 | heap.Push(&h, fragment{offset: 2, vv: vv(1, "1")}) 122 | _, err := h.reassemble() 123 | if err == nil { 124 | t.Errorf("reassemble() did not fail when there was a hole in the packet") 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /protocol/network/fragmentation/reassembler.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package fragmentation 16 | 17 | import ( 18 | "container/heap" 19 | "fmt" 20 | "math" 21 | "sync" 22 | "time" 23 | 24 | "github.com/brewlin/net-protocol/pkg/buffer" 25 | ) 26 | 27 | type hole struct { 28 | first uint16 29 | last uint16 30 | deleted bool 31 | } 32 | 33 | type reassembler struct { 34 | reassemblerEntry 35 | id uint32 36 | size int 37 | mu sync.Mutex 38 | holes []hole 39 | deleted int 40 | heap fragHeap 41 | done bool 42 | creationTime time.Time 43 | } 44 | 45 | func newReassembler(id uint32) *reassembler { 46 | r := &reassembler{ 47 | id: id, 48 | holes: make([]hole, 0, 16), 49 | deleted: 0, 50 | heap: make(fragHeap, 0, 8), 51 | creationTime: time.Now(), 52 | } 53 | r.holes = append(r.holes, hole{ 54 | first: 0, 55 | last: math.MaxUint16, 56 | deleted: false}) 57 | return r 58 | } 59 | 60 | // updateHoles updates the list of holes for an incoming fragment and 61 | // returns true iff the fragment filled at least part of an existing hole. 62 | func (r *reassembler) updateHoles(first, last uint16, more bool) bool { 63 | used := false 64 | for i := range r.holes { 65 | if r.holes[i].deleted || first > r.holes[i].last || last < r.holes[i].first { 66 | continue 67 | } 68 | used = true 69 | r.deleted++ 70 | r.holes[i].deleted = true 71 | if first > r.holes[i].first { 72 | r.holes = append(r.holes, hole{r.holes[i].first, first - 1, false}) 73 | } 74 | if last < r.holes[i].last && more { 75 | r.holes = append(r.holes, hole{last + 1, r.holes[i].last, false}) 76 | } 77 | } 78 | return used 79 | } 80 | 81 | func (r *reassembler) process(first, last uint16, more bool, vv buffer.VectorisedView) (buffer.VectorisedView, bool, int) { 82 | r.mu.Lock() 83 | defer r.mu.Unlock() 84 | consumed := 0 85 | if r.done { 86 | // A concurrent goroutine might have already reassembled 87 | // the packet and emptied the heap while this goroutine 88 | // was waiting on the mutex. We don't have to do anything in this case. 89 | return buffer.VectorisedView{}, false, consumed 90 | } 91 | if r.updateHoles(first, last, more) { 92 | // We store the incoming packet only if it filled some holes. 93 | heap.Push(&r.heap, fragment{offset: first, vv: vv.Clone(nil)}) 94 | consumed = vv.Size() 95 | r.size += consumed 96 | } 97 | // Check if all the holes have been deleted and we are ready to reassamble. 98 | if r.deleted < len(r.holes) { 99 | return buffer.VectorisedView{}, false, consumed 100 | } 101 | res, err := r.heap.reassemble() 102 | if err != nil { 103 | panic(fmt.Sprintf("reassemble failed with: %v. There is probably a bug in the code handling the holes.", err)) 104 | } 105 | return res, true, consumed 106 | } 107 | 108 | func (r *reassembler) tooOld(timeout time.Duration) bool { 109 | return time.Now().Sub(r.creationTime) > timeout 110 | } 111 | 112 | func (r *reassembler) checkDoneOrMark() bool { 113 | r.mu.Lock() 114 | prev := r.done 115 | r.done = true 116 | r.mu.Unlock() 117 | return prev 118 | } 119 | -------------------------------------------------------------------------------- /protocol/network/fragmentation/reassembler_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package fragmentation 16 | 17 | import ( 18 | "math" 19 | "reflect" 20 | "testing" 21 | ) 22 | 23 | type updateHolesInput struct { 24 | first uint16 25 | last uint16 26 | more bool 27 | } 28 | 29 | var holesTestCases = []struct { 30 | comment string 31 | in []updateHolesInput 32 | want []hole 33 | }{ 34 | { 35 | comment: "No fragments. Expected holes: {[0 -> inf]}.", 36 | in: []updateHolesInput{}, 37 | want: []hole{{first: 0, last: math.MaxUint16, deleted: false}}, 38 | }, 39 | { 40 | comment: "One fragment at beginning. Expected holes: {[2, inf]}.", 41 | in: []updateHolesInput{{first: 0, last: 1, more: true}}, 42 | want: []hole{ 43 | {first: 0, last: math.MaxUint16, deleted: true}, 44 | {first: 2, last: math.MaxUint16, deleted: false}, 45 | }, 46 | }, 47 | { 48 | comment: "One fragment in the middle. Expected holes: {[0, 0], [3, inf]}.", 49 | in: []updateHolesInput{{first: 1, last: 2, more: true}}, 50 | want: []hole{ 51 | {first: 0, last: math.MaxUint16, deleted: true}, 52 | {first: 0, last: 0, deleted: false}, 53 | {first: 3, last: math.MaxUint16, deleted: false}, 54 | }, 55 | }, 56 | { 57 | comment: "One fragment at the end. Expected holes: {[0, 0]}.", 58 | in: []updateHolesInput{{first: 1, last: 2, more: false}}, 59 | want: []hole{ 60 | {first: 0, last: math.MaxUint16, deleted: true}, 61 | {first: 0, last: 0, deleted: false}, 62 | }, 63 | }, 64 | { 65 | comment: "One fragment completing a packet. Expected holes: {}.", 66 | in: []updateHolesInput{{first: 0, last: 1, more: false}}, 67 | want: []hole{ 68 | {first: 0, last: math.MaxUint16, deleted: true}, 69 | }, 70 | }, 71 | { 72 | comment: "Two non-overlapping fragments completing a packet. Expected holes: {}.", 73 | in: []updateHolesInput{ 74 | {first: 0, last: 1, more: true}, 75 | {first: 2, last: 3, more: false}, 76 | }, 77 | want: []hole{ 78 | {first: 0, last: math.MaxUint16, deleted: true}, 79 | {first: 2, last: math.MaxUint16, deleted: true}, 80 | }, 81 | }, 82 | { 83 | comment: "Two overlapping fragments completing a packet. Expected holes: {}.", 84 | in: []updateHolesInput{ 85 | {first: 0, last: 2, more: true}, 86 | {first: 2, last: 3, more: false}, 87 | }, 88 | want: []hole{ 89 | {first: 0, last: math.MaxUint16, deleted: true}, 90 | {first: 3, last: math.MaxUint16, deleted: true}, 91 | }, 92 | }, 93 | } 94 | 95 | func TestUpdateHoles(t *testing.T) { 96 | for _, c := range holesTestCases { 97 | r := newReassembler(0) 98 | for _, i := range c.in { 99 | r.updateHoles(i.first, i.last, i.more) 100 | } 101 | if !reflect.DeepEqual(r.holes, c.want) { 102 | t.Errorf("Test \"%s\" produced unexepetced holes. Got %v. Want %v", c.comment, r.holes, c.want) 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /protocol/network/hash/hash.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package hash contains utility functions for hashing. 16 | package hash 17 | 18 | import ( 19 | "encoding/binary" 20 | 21 | "github.com/brewlin/net-protocol/protocol/header" 22 | 23 | "github.com/brewlin/net-protocol/pkg/rand" 24 | ) 25 | 26 | var hashIV = RandN32(1)[0] 27 | 28 | // RandN32 generates a slice of n cryptographic random 32-bit numbers. 29 | func RandN32(n int) []uint32 { 30 | b := make([]byte, 4*n) 31 | if _, err := rand.Read(b); err != nil { 32 | panic("unable to get random numbers: " + err.Error()) 33 | } 34 | r := make([]uint32, n) 35 | for i := range r { 36 | r[i] = binary.LittleEndian.Uint32(b[4*i : (4*i + 4)]) 37 | } 38 | return r 39 | } 40 | 41 | // Hash3Words calculates the Jenkins hash of 3 32-bit words. This is adapted 42 | // from linux. 43 | func Hash3Words(a, b, c, initval uint32) uint32 { 44 | const iv = 0xdeadbeef + (3 << 2) 45 | initval += iv 46 | 47 | a += initval 48 | b += initval 49 | c += initval 50 | 51 | c ^= b 52 | c -= rol32(b, 14) 53 | a ^= c 54 | a -= rol32(c, 11) 55 | b ^= a 56 | b -= rol32(a, 25) 57 | c ^= b 58 | c -= rol32(b, 16) 59 | a ^= c 60 | a -= rol32(c, 4) 61 | b ^= a 62 | b -= rol32(a, 14) 63 | c ^= b 64 | c -= rol32(b, 24) 65 | 66 | return c 67 | } 68 | 69 | // IPv4FragmentHash computes the hash of the IPv4 fragment as suggested in RFC 791. 70 | // 根据id,源ip,目的ip和协议类型得到hash值 71 | func IPv4FragmentHash(h header.IPv4) uint32 { 72 | x := uint32(h.ID())<<16 | uint32(h.Protocol()) 73 | t := h.SourceAddress() 74 | y := uint32(t[0]) | uint32(t[1])<<8 | uint32(t[2])<<16 | uint32(t[3])<<24 75 | t = h.DestinationAddress() 76 | z := uint32(t[0]) | uint32(t[1])<<8 | uint32(t[2])<<16 | uint32(t[3])<<24 77 | return Hash3Words(x, y, z, hashIV) 78 | } 79 | 80 | // IPv6FragmentHash computes the hash of the ipv6 fragment. 81 | // Unlike IPv4, the protocol is not used to compute the hash. 82 | // RFC 2640 (sec 4.5) is not very sharp on this aspect. 83 | // As a reference, also Linux ignores the protocol to compute 84 | // the hash (inet6_hash_frag). 85 | func IPv6FragmentHash(h header.IPv6, f header.IPv6Fragment) uint32 { 86 | t := h.SourceAddress() 87 | y := uint32(t[0]) | uint32(t[1])<<8 | uint32(t[2])<<16 | uint32(t[3])<<24 88 | t = h.DestinationAddress() 89 | z := uint32(t[0]) | uint32(t[1])<<8 | uint32(t[2])<<16 | uint32(t[3])<<24 90 | return Hash3Words(f.ID(), y, z, hashIV) 91 | } 92 | 93 | func rol32(v, shift uint32) uint32 { 94 | return (v << shift) | (v >> ((-shift) & 31)) 95 | } 96 | -------------------------------------------------------------------------------- /protocol/network/ipv4/ip.go: -------------------------------------------------------------------------------- 1 | package ipv4 2 | 3 | import ( 4 | "net" 5 | "strings" 6 | ) 7 | 8 | // InternalInterfaces return internal ip && nic name. 9 | func InternalInterfaces() (ip, nic string) { 10 | inters, err := net.Interfaces() 11 | if err != nil { 12 | return "", "" 13 | } 14 | for _, inter := range inters { 15 | if !strings.HasPrefix(inter.Name, "lo") { 16 | addrs, err := inter.Addrs() 17 | if err != nil { 18 | continue 19 | } 20 | for _, addr := range addrs { 21 | if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 22 | if ipnet.IP.To4() != nil { 23 | return ipnet.IP.String(), inter.Name 24 | } 25 | } 26 | } 27 | } 28 | } 29 | return "", "" 30 | } 31 | -------------------------------------------------------------------------------- /protocol/network/ipv4/ipv4_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ipv4_test 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/brewlin/net-protocol/pkg/waiter" 21 | tcpip "github.com/brewlin/net-protocol/protocol" 22 | "github.com/brewlin/net-protocol/protocol/header" 23 | "github.com/brewlin/net-protocol/protocol/link/channel" 24 | "github.com/brewlin/net-protocol/protocol/link/sniffer" 25 | "github.com/brewlin/net-protocol/protocol/network/ipv4" 26 | "github.com/brewlin/net-protocol/protocol/transport/udp" 27 | "github.com/brewlin/net-protocol/stack" 28 | ) 29 | 30 | func TestExcludeBroadcast(t *testing.T) { 31 | s := stack.New([]string{ipv4.ProtocolName}, []string{udp.ProtocolName}, stack.Options{}) 32 | 33 | const defaultMTU = 65536 34 | id, _ := channel.New(256, defaultMTU, "") 35 | if testing.Verbose() { 36 | id = sniffer.New(id) 37 | } 38 | if err := s.CreateNIC(1, id); err != nil { 39 | t.Fatalf("CreateNIC failed: %v", err) 40 | } 41 | 42 | if err := s.AddAddress(1, ipv4.ProtocolNumber, header.IPv4Broadcast); err != nil { 43 | t.Fatalf("AddAddress failed: %v", err) 44 | } 45 | if err := s.AddAddress(1, ipv4.ProtocolNumber, header.IPv4Any); err != nil { 46 | t.Fatalf("AddAddress failed: %v", err) 47 | } 48 | 49 | s.SetRouteTable([]tcpip.Route{{ 50 | Destination: "\x00\x00\x00\x00", 51 | Mask: "\x00\x00\x00\x00", 52 | Gateway: "", 53 | NIC: 1, 54 | }}) 55 | 56 | randomAddr := tcpip.FullAddress{NIC: 1, Addr: "\x0a\x00\x00\x01", Port: 53} 57 | 58 | var wq waiter.Queue 59 | t.Run("WithoutPrimaryAddress", func(t *testing.T) { 60 | ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 61 | if err != nil { 62 | t.Fatal(err) 63 | } 64 | defer ep.Close() 65 | 66 | // Cannot connect using a broadcast address as the source. 67 | if err := ep.Connect(randomAddr); err != tcpip.ErrNoRoute { 68 | t.Errorf("got ep.Connect(...) = %v, want = %v", err, tcpip.ErrNoRoute) 69 | } 70 | 71 | // However, we can bind to a broadcast address to listen. 72 | if err := ep.Bind(tcpip.FullAddress{Addr: header.IPv4Broadcast, Port: 53, NIC: 1}, nil); err != nil { 73 | t.Errorf("Bind failed: %v", err) 74 | } 75 | }) 76 | 77 | t.Run("WithPrimaryAddress", func(t *testing.T) { 78 | ep, err := s.NewEndpoint(udp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 79 | if err != nil { 80 | t.Fatal(err) 81 | } 82 | defer ep.Close() 83 | 84 | // Add a valid primary endpoint address, now we can connect. 85 | if err := s.AddAddress(1, ipv4.ProtocolNumber, "\x0a\x00\x00\x02"); err != nil { 86 | t.Fatalf("AddAddress failed: %v", err) 87 | } 88 | if err := ep.Connect(randomAddr); err != nil { 89 | t.Errorf("Connect failed: %v", err) 90 | } 91 | }) 92 | } 93 | -------------------------------------------------------------------------------- /protocol/ports/ports_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package ports 16 | 17 | import ( 18 | "testing" 19 | 20 | tcpip "github.com/brewlin/net-protocol/protocol" 21 | ) 22 | 23 | const ( 24 | fakeTransNumber tcpip.TransportProtocolNumber = 1 25 | fakeNetworkNumber tcpip.NetworkProtocolNumber = 2 26 | 27 | fakeIPAddress = tcpip.Address("\x08\x08\x08\x08") 28 | fakeIPAddress1 = tcpip.Address("\x08\x08\x08\x09") 29 | ) 30 | 31 | func TestPortReservation(t *testing.T) { 32 | pm := NewPortManager() 33 | net := []tcpip.NetworkProtocolNumber{fakeNetworkNumber} 34 | 35 | for _, test := range []struct { 36 | port uint16 37 | ip tcpip.Address 38 | want *tcpip.Error 39 | }{ 40 | { 41 | port: 80, 42 | ip: fakeIPAddress, 43 | want: nil, 44 | }, 45 | { 46 | port: 80, 47 | ip: fakeIPAddress1, 48 | want: nil, 49 | }, 50 | { 51 | /* N.B. Order of tests matters! */ 52 | port: 80, 53 | ip: anyIPAddress, 54 | want: tcpip.ErrPortInUse, 55 | }, 56 | { 57 | port: 22, 58 | ip: anyIPAddress, 59 | want: nil, 60 | }, 61 | { 62 | port: 22, 63 | ip: fakeIPAddress, 64 | want: tcpip.ErrPortInUse, 65 | }, 66 | { 67 | port: 0, 68 | ip: fakeIPAddress, 69 | want: nil, 70 | }, 71 | { 72 | port: 0, 73 | ip: fakeIPAddress, 74 | want: nil, 75 | }, 76 | } { 77 | gotPort, err := pm.ReservePort(net, fakeTransNumber, test.ip, test.port) 78 | if err != test.want { 79 | t.Fatalf("ReservePort(.., .., %s, %d) = %v, want %v", test.ip, test.port, err, test.want) 80 | } 81 | if test.port == 0 && (gotPort == 0 || gotPort < FirstEphemeral) { 82 | t.Fatalf("ReservePort(.., .., .., 0) = %d, want port number >= %d to be picked", gotPort, FirstEphemeral) 83 | } 84 | } 85 | 86 | // Release port 22 from any IP address, then try to reserve fake IP 87 | // address on 22. 88 | pm.ReleasePort(net, fakeTransNumber, anyIPAddress, 22) 89 | 90 | if port, err := pm.ReservePort(net, fakeTransNumber, fakeIPAddress, 22); port != 22 || err != nil { 91 | t.Fatalf("ReservePort(.., .., .., %d) = (port %d, err %v), want (22, nil); failed to reserve port after it should have been released", 22, port, err) 92 | } 93 | } 94 | 95 | func TestPickEphemeralPort(t *testing.T) { 96 | pm := NewPortManager() 97 | customErr := &tcpip.Error{} 98 | for _, test := range []struct { 99 | name string 100 | f func(port uint16) (bool, *tcpip.Error) 101 | wantErr *tcpip.Error 102 | wantPort uint16 103 | }{ 104 | { 105 | name: "no-port-available", 106 | f: func(port uint16) (bool, *tcpip.Error) { 107 | return false, nil 108 | }, 109 | wantErr: tcpip.ErrNoPortAvailable, 110 | }, 111 | { 112 | name: "port-tester-error", 113 | f: func(port uint16) (bool, *tcpip.Error) { 114 | return false, customErr 115 | }, 116 | wantErr: customErr, 117 | }, 118 | { 119 | name: "only-port-16042-available", 120 | f: func(port uint16) (bool, *tcpip.Error) { 121 | if port == FirstEphemeral+42 { 122 | return true, nil 123 | } 124 | return false, nil 125 | }, 126 | wantPort: FirstEphemeral + 42, 127 | }, 128 | { 129 | name: "only-port-under-16000-available", 130 | f: func(port uint16) (bool, *tcpip.Error) { 131 | if port < FirstEphemeral { 132 | return true, nil 133 | } 134 | return false, nil 135 | }, 136 | wantErr: tcpip.ErrNoPortAvailable, 137 | }, 138 | } { 139 | t.Run(test.name, func(t *testing.T) { 140 | if port, err := pm.PickEphemeralPort(test.f); port != test.wantPort || err != test.wantErr { 141 | t.Errorf("PickEphemeralPort(..) = (port %d, err %v); want (port %d, err %v)", port, err, test.wantPort, test.wantErr) 142 | } 143 | }) 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /protocol/time.s: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Empty assembly file so empty func definitions work. 16 | -------------------------------------------------------------------------------- /protocol/time_unsafe.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build go1.9 16 | 17 | package tcpip 18 | 19 | import ( 20 | _ "time" // Used with go:linkname. 21 | _ "unsafe" // Required for go:linkname. 22 | ) 23 | 24 | // StdClock implements Clock with the time package. 25 | type StdClock struct{} 26 | 27 | var _ Clock = (*StdClock)(nil) 28 | 29 | //go:linkname now time.now 30 | func now() (sec int64, nsec int32, mono int64) 31 | 32 | // NowNanoseconds implements Clock.NowNanoseconds. 33 | func (*StdClock) NowNanoseconds() int64 { 34 | sec, nsec, _ := now() 35 | return sec*1e9 + int64(nsec) 36 | } 37 | 38 | // NowMonotonic implements Clock.NowMonotonic. 39 | func (*StdClock) NowMonotonic() int64 { 40 | _, _, mono := now() 41 | return mono 42 | } 43 | -------------------------------------------------------------------------------- /protocol/transport/ping/protocol.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package ping contains the implementation of the ICMP and IPv6-ICMP transport 16 | // protocols for use in ping. To use it in the networking stack, this package 17 | // must be added to the project, and 18 | // activated on the stack by passing ping.ProtocolName (or "ping") and/or 19 | // ping.ProtocolName6 (or "ping6") as one of the transport protocols when 20 | // calling stack.New(). Then endpoints can be created by passing 21 | // ping.ProtocolNumber or ping.ProtocolNumber6 as the transport protocol number 22 | // when calling Stack.NewEndpoint(). 23 | package ping 24 | 25 | import ( 26 | "encoding/binary" 27 | "fmt" 28 | 29 | tcpip "github.com/brewlin/net-protocol/protocol" 30 | "github.com/brewlin/net-protocol/pkg/buffer" 31 | "github.com/brewlin/net-protocol/protocol/header" 32 | "github.com/brewlin/net-protocol/stack" 33 | "github.com/brewlin/net-protocol/pkg/waiter" 34 | ) 35 | 36 | const ( 37 | // ProtocolName4 is the string representation of the ping protocol name. 38 | ProtocolName4 = "ping4" 39 | 40 | // ProtocolNumber4 is the ICMP protocol number. 41 | ProtocolNumber4 = header.ICMPv4ProtocolNumber 42 | 43 | // ProtocolName6 is the string representation of the ping protocol name. 44 | ProtocolName6 = "ping6" 45 | 46 | // ProtocolNumber6 is the IPv6-ICMP protocol number. 47 | ProtocolNumber6 = header.ICMPv6ProtocolNumber 48 | ) 49 | 50 | type protocol struct { 51 | number tcpip.TransportProtocolNumber 52 | } 53 | 54 | // Number returns the ICMP protocol number. 55 | func (p *protocol) Number() tcpip.TransportProtocolNumber { 56 | return p.number 57 | } 58 | 59 | func (p *protocol) netProto() tcpip.NetworkProtocolNumber { 60 | switch p.number { 61 | case ProtocolNumber4: 62 | return header.IPv4ProtocolNumber 63 | case ProtocolNumber6: 64 | return header.IPv6ProtocolNumber 65 | } 66 | panic(fmt.Sprint("unknown protocol number: ", p.number)) 67 | } 68 | 69 | // NewEndpoint creates a new ping endpoint. 70 | func (p *protocol) NewEndpoint(stack *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) { 71 | if netProto != p.netProto() { 72 | return nil, tcpip.ErrUnknownProtocol 73 | } 74 | return newEndpoint(stack, netProto, p.number, waiterQueue), nil 75 | } 76 | 77 | // MinimumPacketSize returns the minimum valid ping packet size. 78 | func (p *protocol) MinimumPacketSize() int { 79 | switch p.number { 80 | case ProtocolNumber4: 81 | return header.ICMPv4EchoMinimumSize 82 | case ProtocolNumber6: 83 | return header.ICMPv6EchoMinimumSize 84 | } 85 | panic(fmt.Sprint("unknown protocol number: ", p.number)) 86 | } 87 | 88 | // ParsePorts returns the source and destination ports stored in the given ping 89 | // packet. 90 | func (p *protocol) ParsePorts(v buffer.View) (src, dst uint16, err *tcpip.Error) { 91 | switch p.number { 92 | case ProtocolNumber4: 93 | return 0, binary.BigEndian.Uint16(v[header.ICMPv4MinimumSize:]), nil 94 | case ProtocolNumber6: 95 | return 0, binary.BigEndian.Uint16(v[header.ICMPv6MinimumSize:]), nil 96 | } 97 | panic(fmt.Sprint("unknown protocol number: ", p.number)) 98 | } 99 | 100 | // HandleUnknownDestinationPacket handles packets targeted at this protocol but 101 | // that don't match any existing endpoint. 102 | func (p *protocol) HandleUnknownDestinationPacket(*stack.Route, stack.TransportEndpointID, buffer.VectorisedView) bool { 103 | return true 104 | } 105 | 106 | // SetOption implements TransportProtocol.SetOption. 107 | func (p *protocol) SetOption(option interface{}) *tcpip.Error { 108 | return tcpip.ErrUnknownProtocolOption 109 | } 110 | 111 | // Option implements TransportProtocol.Option. 112 | func (p *protocol) Option(option interface{}) *tcpip.Error { 113 | return tcpip.ErrUnknownProtocolOption 114 | } 115 | 116 | func init() { 117 | stack.RegisterTransportProtocolFactory(ProtocolName4, func() stack.TransportProtocol { 118 | return &protocol{ProtocolNumber4} 119 | }) 120 | 121 | stack.RegisterTransportProtocolFactory(ProtocolName6, func() stack.TransportProtocol { 122 | return &protocol{ProtocolNumber6} 123 | }) 124 | } 125 | -------------------------------------------------------------------------------- /protocol/transport/tcp/client/client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "errors" 5 | "log" 6 | "net" 7 | 8 | "github.com/brewlin/net-protocol/pkg/waiter" 9 | 10 | "sync" 11 | 12 | "github.com/brewlin/net-protocol/pkg/buffer" 13 | tcpip "github.com/brewlin/net-protocol/protocol" 14 | "github.com/brewlin/net-protocol/protocol/network/ipv4" 15 | "github.com/brewlin/net-protocol/protocol/transport/tcp" 16 | "github.com/brewlin/net-protocol/stack" 17 | "github.com/brewlin/net-protocol/stack/stackinit" 18 | ) 19 | 20 | //Client client struct 21 | type Client struct { 22 | s *stack.Stack 23 | ep tcpip.Endpoint 24 | addr tcpip.Address 25 | port int 26 | 27 | //接受队列缓存区 28 | buf buffer.View 29 | bufmu sync.RWMutex 30 | 31 | notifyC chan struct{} 32 | waitEntry waiter.Entry 33 | 34 | remote tcpip.FullAddress 35 | queue waiter.Queue 36 | } 37 | 38 | 39 | //NewClient get new tcp client 40 | func NewClient(addrName string, port int) *Client { 41 | addr := tcpip.Address(net.ParseIP(addrName).To4()) 42 | return &Client{ 43 | addr: tcpip.Address(addr), 44 | port: port, 45 | } 46 | } 47 | 48 | //Set set options 49 | func (c *Client) Set(s *stack.Stack) { 50 | c.s = s 51 | } 52 | 53 | //Connect connect 54 | func (c *Client) Connect() error { 55 | c.s = stack.Pstack 56 | if c.s == nil { 57 | log.Println("stack is nil") 58 | return errors.New("stack is nil") 59 | } 60 | return c.connect(c.s) 61 | } 62 | 63 | func (c *Client) connect(s *stack.Stack) error { 64 | //添加路由 65 | stackinit.AddRoute(c.addr) 66 | c.remote = tcpip.FullAddress{ 67 | Addr: c.addr, 68 | Port: uint16(c.port), 69 | } 70 | var wq waiter.Queue 71 | //新建一个tcp端 72 | ep, err := s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &wq) 73 | if err != nil { 74 | log.Println(err) 75 | return err 76 | } 77 | c.ep = ep 78 | c.queue = wq 79 | 80 | c.waitEntry, c.notifyC = waiter.NewChannelEntry(nil) 81 | wq.EventRegister(&c.waitEntry, waiter.EventOut|waiter.EventIn) 82 | c.ep = ep 83 | terr := c.ep.Connect(c.remote) 84 | if terr == tcpip.ErrConnectStarted { 85 | log.Println("@传输层 tcp/client : Connect is pending...") 86 | <-c.notifyC 87 | terr = ep.GetSockOpt(tcpip.ErrorOption{}) 88 | } 89 | if terr != nil { 90 | log.Println("@传输层 tcp/client : Unable to connect: ", terr) 91 | return terr 92 | } 93 | log.Println("@传输层 tcp/client:Connected") 94 | return nil 95 | } 96 | func (c *Client) Close() { 97 | c.queue.EventUnregister(&c.waitEntry) 98 | c.ep.Close() 99 | log.Println("@传输层 tcp/client :tcp disconnected") 100 | } 101 | 102 | -------------------------------------------------------------------------------- /protocol/transport/tcp/client/get.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "github.com/brewlin/net-protocol/pkg/waiter" 5 | tcpip "github.com/brewlin/net-protocol/protocol" 6 | ) 7 | 8 | //GetAddr 9 | func (c *Client) GetAddr() tcpip.Address { 10 | return c.addr 11 | } 12 | //GetRemoteAddr 13 | func (c *Client) GetRemoteAddr() *tcpip.FullAddress { 14 | return &c.remote 15 | } 16 | //GetQueue 获取接收时间队列 17 | func (c *Client)GetQueue()*waiter.Queue { 18 | return &c.queue 19 | } 20 | //GetNotify 获取事件chan 21 | func (c *Client)GetNotify()chan struct{}{ 22 | return c.notifyC 23 | } 24 | -------------------------------------------------------------------------------- /protocol/transport/tcp/client/read.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "errors" 5 | 6 | tcpip "github.com/brewlin/net-protocol/protocol" 7 | ) 8 | 9 | //Read 一次性读取完缓冲区数据 10 | func (c *Client) Read() ([]byte, error) { 11 | <-c.notifyC 12 | var buf []byte 13 | var err error 14 | for { 15 | v, _, e := c.ep.Read(&c.remote) 16 | if e != nil { 17 | err = e 18 | break 19 | } 20 | buf = append(buf, v...) 21 | } 22 | if buf == nil { 23 | return nil, err 24 | } 25 | return buf, nil 26 | 27 | } 28 | 29 | //Readn 读取固定字节的数据 30 | func (c *Client) Readn(p []byte) (int, error) { 31 | c.bufmu.Lock() 32 | defer c.bufmu.Unlock() 33 | //获取足够长度的字节 34 | if len(p) > len(c.buf) { 35 | 36 | for { 37 | if len(p) <= len(c.buf) { 38 | break 39 | } 40 | buf, _, err := c.ep.Read(&c.remote) 41 | if err != nil { 42 | if err == tcpip.ErrWouldBlock { 43 | //阻塞等待数据 44 | <-c.notifyC 45 | continue 46 | } 47 | return 0, err 48 | } 49 | c.buf = append(c.buf, buf...) 50 | } 51 | } 52 | if len(p) > len(c.buf) { 53 | return 0, errors.New("package len is smaller than p need") 54 | } 55 | 56 | n := copy(p, c.buf) 57 | c.buf = c.buf[len(p):] 58 | return n, nil 59 | } 60 | -------------------------------------------------------------------------------- /protocol/transport/tcp/client/write.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "github.com/brewlin/net-protocol/pkg/buffer" 5 | tcpip "github.com/brewlin/net-protocol/protocol" 6 | ) 7 | //Write 8 | func (c *Client) Write(buf []byte) error { 9 | v := buffer.View(buf) 10 | c.ep.Write(tcpip.SlicePayload(v), 11 | tcpip.WriteOptions{To: &c.remote}) 12 | return nil 13 | } -------------------------------------------------------------------------------- /protocol/transport/tcp/reno.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package tcp 16 | 17 | // renoState stores the variables related to TCP New Reno congestion 18 | // control algorithm. 19 | // 20 | // +stateify savable 21 | type renoState struct { 22 | s *sender 23 | } 24 | 25 | // newRenoCC initializes the state for the NewReno congestion control algorithm. 26 | // 新建 reno 算法对象 27 | func newRenoCC(s *sender) *renoState { 28 | return &renoState{s: s} 29 | } 30 | 31 | // updateSlowStart will update the congestion window as per the slow-start 32 | // algorithm used by NewReno. If after adjusting the congestion window 33 | // we cross the SSthreshold then it will return the number of packets that 34 | // must be consumed in congestion avoidance mode. 35 | // updateSlowStart 将根据NewReno使用的慢启动算法更新拥塞窗口。 36 | // 如果在调整拥塞窗口后我们越过了 SSthreshold ,那么它将返回在拥塞避免模式下必须消耗的数据包的数量。 37 | func (r *renoState) updateSlowStart(packetsAcked int) int { 38 | // Don't let the congestion window cross into the congestion 39 | // avoidance range. 40 | // 在慢启动阶段,每次收到ack,sndCwnd加上已确认的段数 41 | newcwnd := r.s.sndCwnd + packetsAcked 42 | // 判断增大过后的拥塞窗口是否超过慢启动阀值 sndSsthresh, 43 | // 如果超过 sndSsthresh ,将窗口调整为 sndSsthresh 44 | if newcwnd >= r.s.sndSsthresh { 45 | newcwnd = r.s.sndSsthresh 46 | r.s.sndCAAckCount = 0 47 | } 48 | // 是否超过 sndSsthresh, packetsAcked>0表示超过 49 | packetsAcked -= newcwnd - r.s.sndCwnd 50 | // 更新拥塞窗口 51 | r.s.sndCwnd = newcwnd 52 | return packetsAcked 53 | } 54 | 55 | // updateCongestionAvoidance will update congestion window in congestion 56 | // avoidance mode as described in RFC5681 section 3.1 57 | // updateCongestionAvoidance 将在拥塞避免模式下更新拥塞窗口, 58 | // 如RFC5681第3.1节所述 59 | func (r *renoState) updateCongestionAvoidance(packetsAcked int) { 60 | // Consume the packets in congestion avoidance mode. 61 | // sndCAAckCount 累计收到的tcp段数 62 | r.s.sndCAAckCount += packetsAcked 63 | // 如果累计的段数超过当前的拥塞窗口,那么 sndCwnd 加上 sndCAAckCount/sndCwnd 的整数倍 64 | if r.s.sndCAAckCount >= r.s.sndCwnd { 65 | r.s.sndCwnd += r.s.sndCAAckCount / r.s.sndCwnd 66 | r.s.sndCAAckCount = r.s.sndCAAckCount % r.s.sndCwnd 67 | } 68 | } 69 | 70 | // reduceSlowStartThreshold reduces the slow-start threshold per RFC 5681, 71 | // page 6, eq. 4. It is called when we detect congestion in the network. 72 | // 当检测到网络拥塞时,调用 reduceSlowStartThreshold。 73 | // 它将 sndSsthresh 变为 outstanding 的一半。 74 | // sndSsthresh 最小为2,因为至少要比丢包后的拥塞窗口(cwnd=1)来的大,才会进入慢启动阶段。 75 | func (r *renoState) reduceSlowStartThreshold() { 76 | r.s.sndSsthresh = r.s.outstanding / 2 77 | if r.s.sndSsthresh < 2 { 78 | r.s.sndSsthresh = 2 79 | } 80 | } 81 | 82 | // Update updates the congestion state based on the number of packets that 83 | // were acknowledged. 84 | // Update implements congestionControl.Update. 85 | // packetsAcked 表示已确认的tcp段数 86 | func (r *renoState) Update(packetsAcked int) { 87 | // 当拥塞窗口没有超过慢启动阀值的时候,使用慢启动来增大窗口, 88 | // 否则进入拥塞避免阶段 89 | if r.s.sndCwnd < r.s.sndSsthresh { 90 | packetsAcked = r.updateSlowStart(packetsAcked) 91 | if packetsAcked == 0 { 92 | return 93 | } 94 | } 95 | // 进入拥塞避免阶段 96 | r.updateCongestionAvoidance(packetsAcked) 97 | } 98 | 99 | // HandleNDupAcks implements congestionControl.HandleNDupAcks. 100 | // 当收到三个重复ack时,调用 HandleNDupAcks 来处理。 101 | func (r *renoState) HandleNDupAcks() { 102 | // A retransmit was triggered due to nDupAckThreshold 103 | // being hit. Reduce our slow start threshold. 104 | // 减小慢启动阀值 105 | r.reduceSlowStartThreshold() 106 | } 107 | 108 | // HandleRTOExpired implements congestionControl.HandleRTOExpired. 109 | // 当当发生重传包时,调用 HandleRTOExpired 来处理。 110 | func (r *renoState) HandleRTOExpired() { 111 | // We lost a packet, so reduce ssthresh. 112 | // 减小慢启动阀值 113 | r.reduceSlowStartThreshold() 114 | 115 | // Reduce the congestion window to 1, i.e., enter slow-start. Per 116 | // RFC 5681, page 7, we must use 1 regardless of the value of the 117 | // initial congestion window. 118 | // 更新拥塞窗口为1,这样就会重新进入慢启动 119 | r.s.sndCwnd = 1 120 | } 121 | 122 | // PostRecovery implements congestionControl.PostRecovery. 123 | func (r *renoState) PostRecovery() { 124 | // noop. 125 | } 126 | -------------------------------------------------------------------------------- /protocol/transport/tcp/sack.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package tcp 16 | 17 | import ( 18 | "github.com/brewlin/net-protocol/protocol/header" 19 | "github.com/brewlin/net-protocol/pkg/seqnum" 20 | ) 21 | 22 | const ( 23 | // MaxSACKBlocks is the maximum number of SACK blocks stored 24 | // at receiver side. 25 | // MaxSACKBlocks 是接收端存储的最大SACK块数。 26 | MaxSACKBlocks = 6 27 | ) 28 | 29 | // UpdateSACKBlocks updates the list of SACK blocks to include the segment 30 | // specified by segStart->segEnd. If the segment happens to be an out of order 31 | // delivery then the first block in the sack.blocks always includes the 32 | // segment identified by segStart->segEnd. 33 | // tcp的可靠性:UpdateSACKBlocks 更新SACK块列表以包含 segStart-segEnd 指定的段,只有没有被消费掉的seg才会被用来更新sack。 34 | // 如果该段恰好是无序传递,那么sack.blocks中的第一个块总是包括由 segStart-segEnd 标识的段。 35 | func UpdateSACKBlocks(sack *SACKInfo, segStart seqnum.Value, segEnd seqnum.Value, rcvNxt seqnum.Value) { 36 | newSB := header.SACKBlock{Start: segStart, End: segEnd} 37 | if sack.NumBlocks == 0 { 38 | sack.Blocks[0] = newSB 39 | sack.NumBlocks = 1 40 | return 41 | } 42 | var n = 0 43 | for i := 0; i < sack.NumBlocks; i++ { 44 | start, end := sack.Blocks[i].Start, sack.Blocks[i].End 45 | if end.LessThanEq(start) || start.LessThanEq(rcvNxt) { 46 | // Discard any invalid blocks where end is before start 47 | // and discard any sack blocks that are before rcvNxt as 48 | // those have already been acked. 49 | continue 50 | } 51 | if newSB.Start.LessThanEq(end) && start.LessThanEq(newSB.End) { 52 | // Merge this SACK block into newSB and discard this SACK 53 | // block. 54 | if start.LessThan(newSB.Start) { 55 | newSB.Start = start 56 | } 57 | if newSB.End.LessThan(end) { 58 | newSB.End = end 59 | } 60 | } else { 61 | // Save this block. 62 | sack.Blocks[n] = sack.Blocks[i] 63 | n++ 64 | } 65 | } 66 | if rcvNxt.LessThan(newSB.Start) { 67 | // If this was an out of order segment then make sure that the 68 | // first SACK block is the one that includes the segment. 69 | // 70 | // See the first bullet point in 71 | // https://tools.ietf.org/html/rfc2018#section-4 72 | if n == MaxSACKBlocks { 73 | // If the number of SACK blocks is equal to 74 | // MaxSACKBlocks then discard the last SACK block. 75 | n-- 76 | } 77 | for i := n - 1; i >= 0; i-- { 78 | sack.Blocks[i+1] = sack.Blocks[i] 79 | } 80 | sack.Blocks[0] = newSB 81 | n++ 82 | } 83 | sack.NumBlocks = n 84 | } 85 | 86 | // TrimSACKBlockList updates the sack block list by removing/modifying any block 87 | // where start is < rcvNxt. 88 | // tcp的可靠性:TrimSACKBlockList 通过删除/修改 start为 len(c.buf) { 35 | 36 | for { 37 | if len(p) <= len(c.buf) { 38 | break 39 | } 40 | buf, _, err := c.ep.Read(&c.remote) 41 | if err != nil { 42 | if err == tcpip.ErrWouldBlock { 43 | //阻塞等待数据 44 | <-c.notifyC 45 | continue 46 | } 47 | return 0, err 48 | } 49 | c.buf = append(c.buf, buf...) 50 | } 51 | } 52 | if len(p) > len(c.buf) { 53 | return 0, errors.New("package len is smaller than p need") 54 | } 55 | 56 | n := copy(p, c.buf) 57 | c.buf = c.buf[len(p):] 58 | return n, nil 59 | } 60 | -------------------------------------------------------------------------------- /protocol/transport/udp/client/write.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "github.com/brewlin/net-protocol/pkg/buffer" 5 | tcpip "github.com/brewlin/net-protocol/protocol" 6 | ) 7 | //Write 8 | func (c *Client) Write(buf []byte) *tcpip.Error { 9 | v := buffer.View(buf) 10 | for{ 11 | _,ch,err := c.ep.Write(tcpip.SlicePayload(v), 12 | tcpip.WriteOptions{To: &c.remote}) 13 | if err == tcpip.ErrWouldBlock { 14 | <-ch 15 | continue 16 | } 17 | return err 18 | } 19 | } -------------------------------------------------------------------------------- /protocol/transport/udp/protocol.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package udp contains the implementation of the UDP transport protocol. To use 16 | // it in the networking stack, this package must be added to the project, and 17 | // activated on the stack by passing udp.ProtocolName (or "udp") as one of the 18 | // transport protocols when calling stack.New(). Then endpoints can be created 19 | // by passing udp.ProtocolNumber as the transport protocol number when calling 20 | // Stack.NewEndpoint(). 21 | package udp 22 | 23 | import ( 24 | tcpip "github.com/brewlin/net-protocol/protocol" 25 | "github.com/brewlin/net-protocol/pkg/buffer" 26 | "github.com/brewlin/net-protocol/protocol/header" 27 | "github.com/brewlin/net-protocol/stack" 28 | "github.com/brewlin/net-protocol/pkg/waiter" 29 | ) 30 | 31 | const ( 32 | // ProtocolName is the string representation of the udp protocol name. 33 | ProtocolName = "udp" 34 | 35 | // ProtocolNumber is the udp protocol number. 36 | ProtocolNumber = header.UDPProtocolNumber 37 | ) 38 | 39 | // tcpip.Endpoint 接口的UDP协议实现 40 | type protocol struct{} 41 | 42 | // Number returns the udp protocol number. 43 | func (*protocol) Number() tcpip.TransportProtocolNumber { 44 | return ProtocolNumber 45 | } 46 | 47 | // NewEndpoint creates a new udp endpoint. 48 | func (*protocol) NewEndpoint(stack *stack.Stack, netProto tcpip.NetworkProtocolNumber, 49 | waiterQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) { 50 | return newEndpoint(stack, netProto, waiterQueue), nil 51 | } 52 | 53 | // MinimumPacketSize returns the minimum valid udp packet size. 54 | func (*protocol) MinimumPacketSize() int { 55 | return header.UDPMinimumSize 56 | } 57 | 58 | // ParsePorts returns the source and destination ports stored in the given udp 59 | // packet. 60 | func (*protocol) ParsePorts(v buffer.View) (src, dst uint16, err *tcpip.Error) { 61 | h := header.UDP(v) 62 | return h.SourcePort(), h.DestinationPort(), nil 63 | } 64 | 65 | // HandleUnknownDestinationPacket handles packets targeted at this protocol but 66 | // that don't match any existing endpoint. 67 | func (p *protocol) HandleUnknownDestinationPacket(*stack.Route, stack.TransportEndpointID, buffer.VectorisedView) bool { 68 | return true 69 | } 70 | 71 | // SetOption implements TransportProtocol.SetOption. 72 | func (p *protocol) SetOption(option interface{}) *tcpip.Error { 73 | return tcpip.ErrUnknownProtocolOption 74 | } 75 | 76 | // Option implements TransportProtocol.Option. 77 | func (p *protocol) Option(option interface{}) *tcpip.Error { 78 | return tcpip.ErrUnknownProtocolOption 79 | } 80 | 81 | func init() { 82 | stack.RegisterTransportProtocolFactory(ProtocolName, func() stack.TransportProtocol { 83 | return &protocol{} 84 | }) 85 | } 86 | -------------------------------------------------------------------------------- /resource/arp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brewlin/net-protocol/cc1b50db26219b6aedfbed3942273f69762c5ac2/resource/arp.png -------------------------------------------------------------------------------- /resource/dns_client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brewlin/net-protocol/cc1b50db26219b6aedfbed3942273f69762c5ac2/resource/dns_client.png -------------------------------------------------------------------------------- /resource/dns_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brewlin/net-protocol/cc1b50db26219b6aedfbed3942273f69762c5ac2/resource/dns_server.png -------------------------------------------------------------------------------- /resource/e1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brewlin/net-protocol/cc1b50db26219b6aedfbed3942273f69762c5ac2/resource/e1.png -------------------------------------------------------------------------------- /resource/e2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brewlin/net-protocol/cc1b50db26219b6aedfbed3942273f69762c5ac2/resource/e2.png -------------------------------------------------------------------------------- /resource/http.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brewlin/net-protocol/cc1b50db26219b6aedfbed3942273f69762c5ac2/resource/http.png -------------------------------------------------------------------------------- /resource/websocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brewlin/net-protocol/cc1b50db26219b6aedfbed3942273f69762c5ac2/resource/websocket.png -------------------------------------------------------------------------------- /resource/wm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brewlin/net-protocol/cc1b50db26219b6aedfbed3942273f69762c5ac2/resource/wm.png -------------------------------------------------------------------------------- /stack/stackinit/init.go: -------------------------------------------------------------------------------- 1 | package stackinit 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "strings" 7 | 8 | "github.com/brewlin/net-protocol/config" 9 | 10 | "github.com/brewlin/net-protocol/protocol/link/fdbased" 11 | "github.com/brewlin/net-protocol/protocol/link/tuntap" 12 | "github.com/brewlin/net-protocol/protocol/transport/udp" 13 | 14 | "github.com/brewlin/net-protocol/protocol/network/arp" 15 | "github.com/brewlin/net-protocol/protocol/network/ipv4" 16 | "github.com/brewlin/net-protocol/protocol/transport/tcp" 17 | "github.com/brewlin/net-protocol/stack" 18 | 19 | tcpip "github.com/brewlin/net-protocol/protocol" 20 | ) 21 | 22 | //SetRoute 设置该路由信息 23 | func AddRoute(addr tcpip.Address) { 24 | //未配置, 则自动随机获取网卡ipv4地址 25 | firstIp, firstNic := ipv4.InternalInterfaces() 26 | if config.HardwardIp == "" { 27 | config.HardwardIp = firstIp 28 | } 29 | if config.HardwardName == "" { 30 | config.HardwardName = firstNic 31 | } 32 | //添加默认路由 33 | stack.Pstack.AddRouteTable(tcpip.Route{ 34 | 35 | Destination: tcpip.Address(strings.Repeat("\x00", len(addr))), 36 | Mask: tcpip.AddressMask(strings.Repeat("\x00", len(addr))), 37 | Gateway: tcpip.Address(net.ParseIP(config.HardwardIp).To4()), 38 | NIC: 1, 39 | }) 40 | } 41 | func init() { 42 | //如果已经存在 p 指向的stack 则不需要在初始化 43 | if stack.Pstack != nil { 44 | return 45 | } 46 | log.Printf("tap :%v", config.NicName) 47 | 48 | //解析mac地址 49 | maddr, err := net.ParseMAC(*config.Mac) 50 | if err != nil { 51 | log.Fatal(*config.Mac) 52 | } 53 | 54 | //虚拟网卡配置 55 | conf := &tuntap.Config{ 56 | Name: config.NicName, 57 | Mode: tuntap.TAP, 58 | } 59 | var fd int 60 | //新建虚拟网卡 61 | fd, err = tuntap.NewNetDev(conf) 62 | if err != nil { 63 | log.Fatal(err) 64 | } 65 | //抽象网卡层接口 66 | linkID := fdbased.New(&fdbased.Options{ 67 | FD: fd, 68 | MTU: 1500, 69 | Address: tcpip.LinkAddress(maddr), 70 | ResolutionRequired: true, 71 | }) 72 | //新建相关协议的协议栈 73 | s := stack.New([]string{ipv4.ProtocolName, arp.ProtocolName}, []string{tcp.ProtocolName, udp.ProtocolName}, stack.Options{}) 74 | //新建抽象网卡 75 | if err := s.CreateNamedNIC(1, "vnic1", linkID); err != nil { 76 | log.Fatal(err) 77 | } 78 | var proto = ipv4.ProtocolNumber 79 | //在该协议栈上添加和注册相关的网络层协议 也就是注册本地地址 80 | if err := s.AddAddress(1, proto, config.LocalAddres); err != nil { 81 | log.Fatal(err) 82 | } 83 | //在该协议栈上添加和注册arp协议 84 | if err := s.AddAddress(1, arp.ProtocolNumber, arp.ProtocolAddress); err != nil { 85 | log.Fatal(err) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /tcp-api.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brewlin/net-protocol/cc1b50db26219b6aedfbed3942273f69762c5ac2/tcp-api.md -------------------------------------------------------------------------------- /tool/Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | go build -x -a up.go 3 | go build -x -a down.go 4 | -------------------------------------------------------------------------------- /tool/README.md: -------------------------------------------------------------------------------- 1 | # tool 2 | ## 注意 3 | 工具默认会更改本地物理网卡的防火墙入站出站规则,以及数据包转发机制 4 | ## 配置 5 | ``` 6 | > make 7 | ``` 8 | ## @虚拟网卡管理 9 | 启动网卡 10 | ``` 11 | > sudo ./up 12 | 13 | > ifconfig 14 | tap Link encap:Ethernet HWaddr 3e:80:55:c6:48:10 15 | inet addr:192.168.1.1 Bcast:0.0.0.0 Mask:255.255.255.0 16 | UP BROADCAST MULTICAST MTU:1500 Metric:1 17 | RX packets:0 errors:0 dropped:0 overruns:0 frame:0 18 | TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 19 | collisions:0 txqueuelen:1000 20 | RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) 21 | ``` 22 | 23 | 关闭网卡 24 | ``` 25 | > sudo ./down 26 | 27 | ``` -------------------------------------------------------------------------------- /tool/down.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/brewlin/net-protocol/config" 6 | 7 | "github.com/brewlin/net-protocol/protocol/link/tuntap" 8 | ) 9 | 10 | func main() { 11 | //关闭网卡 12 | if err := tuntap.DelTap(config.NicName); err != nil { 13 | fmt.Println(err) 14 | return 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tool/up.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os/exec" 6 | 7 | "github.com/brewlin/net-protocol/config" 8 | 9 | "github.com/brewlin/net-protocol/protocol/link/tuntap" 10 | "github.com/brewlin/net-protocol/protocol/network/ipv4" 11 | ) 12 | 13 | func main() { 14 | //未配置, 则自动随机获取网卡ipv4地址 15 | firstIp, firstNic := ipv4.InternalInterfaces() 16 | if config.HardwardIp == "" { 17 | config.HardwardIp = firstIp 18 | } 19 | if config.HardwardName == "" { 20 | config.HardwardName = firstNic 21 | } 22 | //创建网卡 23 | if err := tuntap.CreateTap(config.NicName); err != nil { 24 | fmt.Println(err) 25 | return 26 | } 27 | //启动网卡 28 | if err := tuntap.SetLinkUp(config.NicName); err != nil { 29 | fmt.Println(err) 30 | return 31 | } 32 | //添加路由 33 | if err := tuntap.SetRoute(config.NicName, config.Cidrname); err != nil { 34 | fmt.Println(err) 35 | return 36 | } 37 | //开启防火墙规则 nat数据包转发 38 | if err := IpForwardAndNat(); err != nil { 39 | fmt.Println(err) 40 | tuntap.DelTap(config.NicName) 41 | return 42 | } 43 | select {} 44 | } 45 | func IpForwardAndNat() (err error) { 46 | //清楚本地物联网看的数据包规则, 模拟防火墙 47 | //out, cmdErr := exec.Command("iptables", "-F").CombinedOutput() 48 | //if cmdErr != nil { 49 | // err = fmt.Errorf("iptables -F %v:%v", cmdErr, string(out)) 50 | // return 51 | //} 52 | 53 | out, cmdErr := exec.Command("iptables", "-P", "INPUT", "ACCEPT").CombinedOutput() 54 | if cmdErr != nil { 55 | err = fmt.Errorf("iptables -P INPUT ACCEPT %v:%v", cmdErr, string(out)) 56 | return 57 | } 58 | out, cmdErr = exec.Command("iptables", "-P", "FORWARD", "ACCEPT").CombinedOutput() 59 | if cmdErr != nil { 60 | err = fmt.Errorf("iptables -P FORWARD ACCEPT %v:%v", cmdErr, string(out)) 61 | return 62 | } 63 | out, cmdErr = exec.Command("iptables", "-t", "nat", "-A", "POSTROUTING", "-s", config.Cidrname, "-o", config.HardwardName, "-j", "MASQUERADE").CombinedOutput() 64 | if cmdErr != nil { 65 | err = fmt.Errorf("iptables nat %v:%v", cmdErr, string(out)) 66 | return 67 | } 68 | return 69 | } 70 | -------------------------------------------------------------------------------- /udp-api.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brewlin/net-protocol/cc1b50db26219b6aedfbed3942273f69762c5ac2/udp-api.md -------------------------------------------------------------------------------- /websocket-api.md: -------------------------------------------------------------------------------- 1 | # websocket protocol api 2 | 3 | ## @start 4 | 初始化阶段和`httpserver`一致、新建httpserver、设置路由、启动监听服务 5 | ``` 6 | // r *http.Request, w *http.Response 7 | // Upgrade 为校验websocket协议, 并将http协议升级为websocket协议。并接管http协议流程,直接进行tcp通讯保持连接, 8 | c, err := websocket.Upgrade(r, w) 9 | 10 | //循环处理数据,接受数据,然后返回 11 | for { 12 | //读取客户端数据,该方法一直阻塞直到收到客户端数据,会触发通道取消阻塞 13 | message, err := c.ReadData() 14 | //发送数据给客户端,封装包头包体,调用tcpWrite 封装tcp包头,写入网络层 封装ip包头、写入链路层 封装以太网包头、写入网卡 15 | c.SendData([]byte("hello")) 16 | } 17 | ``` --------------------------------------------------------------------------------