xv6 network-net 3

最近土法煉鋼完成三方交握的部分,沒錯這個實驗還在繼續,為了證明最初的概念是對的。

server

我們要完成的是三方交握的第一階段,也就是 bind - listening - accept 能不能節省掉這個步驟是可以的 當我把sockecvudp while 迴圈裡 if判斷是拿掉的當下就是變成所有流量只要有socket 監聽就可以直接回傳。

tcp header

目前就已經整合進修改過後的xv6 kernel 可以對一般的socket 進行到三方交握階段,

multi-network card qemu tap

透過這些設定,可以讓我們的xv6 支援更多張網卡

bahs
    ip tuntap add mode tap name tap0
    ip addr add 172.16.100.1/24 dev tap0
    ip link set tap0 up
makefile
# QEMUOPTS += -netdev user,id=net0,hostfwd=udp::$(FWDPORT)-:2000,hostfwd=tcp::7-:7 -object filter-dump,id=net0,netdev=net0,file=packets.pcap
# QEMUOPTS += -device e1000,netdev=net0,bus=pcie.0

QEMUOPTS += -netdev tap,id=net1,ifname=tap0  -object filter-dump,id=net1,netdev=net1,file=packets2.pcap
QEMUOPTS += -device e1000,netdev=net1

debug checksuming

最主要的部份如果真的要實現一個tcp 協議需要對封包處理很熟悉,如果有多張網卡的情況可以透過下列指令關閉網卡的checksum 驗證,不然你的封包會莫名其妙地消失 ethtool -K ethx tx off rx off 下列網卡就是針對 tap0 但是可以看到 他寫的是fixed (有關等於沒關 下列是出現封包遺失階段的畫面,網路上資料非常少

server 可以看到有發送syn/ack 但是client遲遲不能解析封包

沒有gui介面可以透過

bash
sudo tcpdump -i tap0 -nn tcp

我找了一個https://github.com/pandax381/xv6-net 虛擬機可以研究了一段時間,稍微研究了他的封包之間的協議可以發現上方是對方的封包訊息,下方是我的

透過

bash
netstat --statistics --tcp

可以看到我們的封包 被網卡拋棄了!

在檢查碼的這部分我發現我的檢查碼每次算會跟真實checksuming 差

c
uint16 tmp = 0x4fb;

開啟wireshark 可以看到封包checksum狀況 這是錯誤範例

後面還有異動幾個版本,最後結論就是 最後懶得改了直接 答案-4fb

c
static void
net_rx_udp(struct mbuf *m, uint16 len, struct ip *iphdr)
{
  struct tcp *udphdr, *udphdr2;
  uint16 src;
  uint16 dst;
  uint32 tmp, seq;

  uint8 flg;
  uint8 flg2;
  uint8 dst1;
  uint8 dst2;
  uint8 dst3;
  uint8 dst4;
  uint32 ack;
  // uint32 sip;
  uint16 sport, dport;
  printf("test16\n");
  struct mbuf *m2;

  m2 = mbufalloc(MBUF_DEFAULT_HEADROOM);
  udphdr = mbufpullhdr(m, *udphdr);
  udphdr2 = mbufpushhdr(m2, (*udphdr2));
  if (!udphdr)
    goto fail;
  printf("pre recv\n");
  // // TODO: validate UDP checksum

  // // validate lengths reported in headers
  // if (ntohs(udphdr->ulen) != len)
  //   goto fail;
  // len -= sizeof(*udphdr);
  // if (len > m->len)
  //   goto fail;
  // // minimum packet size could be larger than the payload
  // mbuftrim(m, m->len - len);
  // printf("test14\n");
  // // parse the necessary fields

  src = ntohl(iphdr->ip_src);
  tmp = udphdr->dst;
  udphdr->dst = udphdr->src;
  udphdr->src = tmp;
  udphdr2->src = udphdr->dst;
  udphdr2->dst = udphdr->src;

  // udphdr2->src = udphdr->dst;
  // udphdr2->dst = udphdr->src;
  //   udphdr2->seq = 0;
  // udphdr2->ack = 0;
  // udphdr2->off = 0;
  // udphdr2->win = 0;
  // udphdr2->sum = 0;
  // udphdr2->urg =0;

  //  uint16 src;
  //   uint16 dst;
  //   uint32 seq;
  //   uint32 ack;
  //   uint8  off;
  //   uint8  flg;
  //   uint16 win;
  //   uint16 sum;
  //   uint16 urg;
  dst = ntohs(udphdr->dst);
  seq = udphdr->seq;
  flg = udphdr->flg;
  flg2 = 18;

  dst = (iphdr->ip_src << 24) | (iphdr->ip_src << 16) | (iphdr->ip_src << 8) | (iphdr->ip_src << 0);
  dst1 = (iphdr->ip_src >> 24);
  dst2 = (iphdr->ip_src >> 16);
  dst3 = (iphdr->ip_src >> 8);
  dst4 = (iphdr->ip_src >> 0);

  ack = udphdr->ack;

  //  | (0 << 16) | (2 << 8) | (2 << 0);
  printf("dst%u\n", dst);
  printf("src%u\n", src);
  // printf("dst %u\n", udphdr->dst);
  printf("src%d\n", ntohs(udphdr->src));
  printf("dst %d\n", ntohs(udphdr->dst));
  printf("seq %u\n", ntohl(seq));
  printBits(flg);
  printBits(flg2);

  printf("flg %d\n", flg);
  printf("flg2 %d\n", flg2);
  printf("addr4 %d\n", dst4);
  printf("addr3 %d\n", dst3);
  printf("addr2 %d\n", dst2);
  printf("addr1 %d\n", dst1);
  dst1 = (iphdr->ip_dst >> 24);
  dst2 = (iphdr->ip_dst >> 16);
  dst3 = (iphdr->ip_dst >> 8);
  dst4 = (iphdr->ip_dst >> 0);
  printf("addr4 %d\n", dst4);
  printf("addr3 %d\n", dst3);
  printf("addr2 %d\n", dst2);
  printf("addr1 %d\n", dst1);

  printf("ack %u\n", ntohl(ack));
  printf("seq  ntohs %u\n", ntohs(seq) + 1);
  printf("seq  ntohl %u\n", ntohl(seq) + 1);

  udphdr->flg = flg2;
  if (stseq == 0)
  {
    udphdr->seq = htonl(ntohl(seq) + 99);
  }
  else
  {
    udphdr->seq = htonl(ntohl(stseq) + 1);
    stseq = ntohl(stseq) + 1;
  }
  // 172.17.35.175
  //  tmp = (192 << 24) | (168<< 16) | (100<< 8) | (1 << 0);
  udphdr2->src = udphdr->src;
  udphdr2->dst = udphdr->dst;
  udphdr2->ack = htonl(ntohl(seq) + 1);

  udphdr2->seq = htonl(ntohl(seq) + 123123123);
  udphdr2->flg = flg2;
  udphdr2->off = (sizeof(struct tcp) >> 2) << 4;
  udphdr2->win = udphdr->win;
  udphdr2->sum = 0;
  udphdr2->urg = 0;
  // udphdr2->option = udphdr->option;
  uint32 pseudo = 0;
  // tmp = (172 << 24) | (16 << 16) | (100 << 8) | (2 << 0);
  // tmp = (10 << 24) | (0 << 16) | (2 << 8) | (15 << 0);
  pseudo += ((local_ip) >> 16) & 0xffff;
  pseudo += (local_ip)&0xffff;
  // tmp = (172 << 24) | (16 << 16) | (100 << 8) | (1 << 0);
  tmp = (172 << 24) | (16 << 16) | (100 << 8) | (1 << 0);
  pseudo += (tmp >> 16) & 0xffff;
  pseudo += tmp & 0xffff;
  pseudo += htons((uint16)IP_PROTOCOL_TCP);
  pseudo += htons(sizeof(struct tcp));
  uint16 tmp2 = 0x4fb;
  printf("%u\n", tmp2);
  // udphdr2->sum =cksum16((uint16 *)udphdr2, sizeof(struct tcp), pseudo);
  udphdr2->sum = cksum16((uint16 *)udphdr2, sizeof(struct tcp), pseudo);
  printf("%u\n", udphdr2->sum);
  printf("%u\n", udphdr2->sum + tmp2);
  printf("%u\n", htons(udphdr2->sum));
  printf("%u\n", htons(tmp2));
  printf("%u\n", htons(udphdr2->sum) + tmp2);
  udphdr2->sum = htons(htons(udphdr2->sum) + tmp2);
  printf("%u\n", htons(udphdr2->sum) + htons(tmp2));
  uint32 pseudo2 = 0;
  // tmp = (172 << 24) | (16 << 16) | (100 << 8) | (2 << 0);
  // tmp = (10 << 24) | (0 << 16) | (2 << 8) | (15 << 0);
  pseudo2 += (local_ip) >> 16;
  pseudo2 += (local_ip)&0xffff;
  // tmp = (172 << 24) | (16 << 16) | (100 << 8) | (1 << 0);
  // 3  0.005475    172.29.64.1 10.0.2.15   TCP 58  58866 → 11111 [SYN] Seq=0 Win=65535 Len=0 MSS=1460
  tmp = (172 << 24) | (16 << 16) | (100 << 8) | (1 << 0);
  pseudo2 += tmp >> 16;
  pseudo2 += tmp & 0xffff;
  pseudo2 += htons((uint16)IP_PROTOCOL_TCP);
  pseudo2 += htons(sizeof(struct tcp));
  // in_cksum()
  if (cksum16((uint16 *)udphdr2, sizeof(struct tcp), pseudo2) != 0)
  {

    printf("tcp checksum error!\n");
  }
  else
    printf("tcp checksum ok!\n");
  //  mbuftrim(m2,4)
  printf("%x\n", cksum16((uint16 *)udphdr2, sizeof(struct tcp), pseudo));
  printf("%x\n", cksum16((uint16 *)udphdr2, sizeof(struct tcp), pseudo2));
  //  uint16 src;
  //   uint16 dst;
  //   uint32 seq;
  //   uint32 ack;
  //   uint8  off;
  //   uint8  flg;
  //   uint16 win;
  //   uint16 sum;
  //   uint16 urg;
  //  printf("seq  ntohs %u\n", ntohs(seq));
  //  printf("seq  ntohs %u\n", ntohl( seq));
  //  printf("ack %u\n", ntohl ( udphdr->ack ));
  udphdr->ack = htonl(ntohl(seq) + 1);

  ack = udphdr2->seq;
  seq = udphdr2->ack;
  // uint8_t *buf;
  // memcpy(udphdr2 + 1, buf, sizeof(20));
  printf("ack %u\n", ntohl(ack));
  printf("seq %u\n", ntohl(seq));
  // struct udp *udphdr;
  // udphdr = mbufpushhdr(m2, *udphdr);
  // // put the UDP header
  // udphdr = mbufpushhdr(m, *udphdr);
  // udphdr->sport = htons(sport);
  // udphdr->dport = htons(dport);
  // udphdr->ulen = htons(m->len);
  // udphdr->sum = 0; // zero means no checksum is provided
  // // 172.18.86.160
  // R(172, 16, 100, 2)

  tmp = (172 << 24) | (16 << 16) | (100 << 8) | (1 << 0);
  // now on to the IP layer
  // struct mbuf *m2;
  //   m2 = mbufalloc(MBUF_DEFAULT_HEADROOM);
  // if (!m2)
  //   return -1;

  // if (copyin(pr->pagetable, mbufput(m, n), addr, n) == -1)
  // {
  //   mbuffree(m);
  //   return -1;
  // }

  // udphdr = mbufpullhdr(m, *udphdr);
  sport = 1;
  dport = 2;
  printf("src%d\n", ntohs(udphdr->src));
  printf("dst %d\n", ntohs(udphdr->dst));
  printf("%d\n", sizeof(udphdr2));
  printf("%d\n", sizeof(udphdr));
  // char *obuf = "a message from xv6!";
  //  mbufput(m2, sizeof(obuf));
  // m2->len = m2->len+sizeof(obuf);
  if (count222 == 0)
  {
    flg2 = (1 << 4) | (1 << 1);
    udphdr2->flg = flg2;

    net_tx_ip(m2, IPPROTO_TCP, tmp);
    //  net_tx_ip(m2, IPPROTO_TCP, tmp);
    //   net_tx_ip(m2, IPPROTO_TCP, tmp);
    //    net_tx_ip(m2, IPPROTO_TCP, tmp);
    //     net_tx_ip(m2, IPPROTO_TCP, tmp);
    //      net_tx_ip(m2, IPPROTO_TCP, tmp);

    // net_tx_ip(m2, IPPROTO_TCP, tmp);
    // mbuffree(m2);
    count222++;
    mbuffree(m2);
  }
  else
  {

    //  flg2 = (1 << 4);
    //    udphdr2->flg = flg2;
    //  net_tx_ip(m, IPPROTO_TCP, tmp);
    //  udphdr2->flg = flg2;
    // net_tx_ip(m2, IPPROTO_TCP, tmp);
  }

  // }
  // else
  sockrecvudp2(m, tmp, dport, sport);
  // sip = htonl(local_ip);;
  // sockrecvudp(m, sip, dport, sport);
  // printf("-------------------\n");
  // sockrecvudp2(m, tmp, dport, sport);
  return;

fail:
  mbuffree(m);
}

算是比較作弊的方式,最近比較忙沒空看檢查碼這部分哪裡有問題,最後看到我的程式碼成功收到來自xv6 的確認封包。 這些問題解決完後面要做的事情就是

增加http 協議和 arp 快取,要看有沒有時間去弄了,最近整理一下再放github

References