├── .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 | 
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 | 
--------------------------------------------------------------------------------
/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 | 
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 | 
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 |
SUCCESSgithub.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 | 
--------------------------------------------------------------------------------
/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 = "ERRORSOMETING WRONG
"
41 | const default_success_msg = "SUCCESSgithub.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 | ```
--------------------------------------------------------------------------------