├── .gitignore ├── 02-protocol └── fct_exp.py ├── 03-socket ├── example │ ├── Makefile │ ├── echo-client.c │ └── echo-server.c ├── simple-http │ ├── Makefile │ ├── http-client.c │ ├── http-server.c │ └── save-http-client.c └── topo.py ├── 04-broadcast ├── Makefile ├── broadcast.c ├── device_internal.c ├── example │ └── list_example.c ├── include │ ├── base.h │ ├── ether.h │ ├── headers.h │ ├── list.h │ ├── log.h │ └── types.h ├── main.c ├── ring_bw.py ├── scripts │ ├── disable_ipv6.sh │ └── disable_offloading.sh └── three_nodes_bw.py ├── 05-switching ├── Makefile ├── broadcast.c ├── device_internal.c ├── example │ └── pthread_example.c ├── include │ ├── base.h │ ├── ether.h │ ├── hash.h │ ├── list.h │ ├── log.h │ ├── mac.h │ ├── types.h │ └── utils.h ├── mac.c ├── main.c ├── scripts │ ├── disable_ipv6.sh │ └── disable_offloading.sh └── three_nodes_bw.py ├── 06-stp ├── Makefile ├── broadcast.c ├── device_internal.c ├── four_node_ring.py ├── host_four_node_ring.py ├── include │ ├── base.h │ ├── ether.h │ ├── hash.h │ ├── list.h │ ├── log.h │ ├── mac.h │ ├── stp.h │ ├── stp_proto.h │ ├── stp_timer.h │ ├── types.h │ └── utils.h ├── larger_net.py ├── mac.c ├── main.c ├── scripts │ ├── disable_ipv6.sh │ └── disable_offloading.sh ├── stp.c └── stp_timer.c ├── 07-bufferbloat ├── mitigate_bufferbloat.py ├── produce_iperf_data.py ├── reproduce_bufferbloat.py └── utils.py ├── 09-router ├── Makefile ├── arp.c ├── arpcache.c ├── complex_router_topo.py ├── device_internal.c ├── icmp.c ├── include │ ├── arp.h │ ├── arpcache.h │ ├── base.h │ ├── checksum.h │ ├── ether.h │ ├── hash.h │ ├── icmp.h │ ├── ip.h │ ├── list.h │ ├── log.h │ ├── rtable.h │ ├── types.h │ └── utils.h ├── ip.c ├── ip_base.c ├── main.c ├── router_topo.py ├── rtable.c ├── rtable_internal.c └── scripts │ ├── disable_arp.sh │ ├── disable_icmp.sh │ ├── disable_ip_forward.sh │ ├── disable_ipv6.sh │ └── disable_offloading.sh ├── 10-lookup ├── Makefile ├── include │ ├── binary.h │ ├── ip.h │ └── trie.h ├── main.c ├── test.sh └── trie.c ├── 11-mopsf ├── Makefile ├── arp.c ├── arpcache.c ├── device_internal.c ├── icmp.c ├── include │ ├── arp.h │ ├── arpcache.h │ ├── base.h │ ├── checksum.h │ ├── ether.h │ ├── icmp.h │ ├── ip.h │ ├── list.h │ ├── log.h │ ├── mospf_daemon.h │ ├── mospf_database.h │ ├── mospf_nbr.h │ ├── mospf_proto.h │ ├── mospf_route.h │ ├── rtable.h │ └── types.h ├── ip.c ├── ip_base.c ├── main.c ├── mospf_daemon.c ├── mospf_database.c ├── mospf_nbr.c ├── mospf_proto.c ├── mospf_route.c ├── rtable.c ├── rtable_internal.c ├── scripts │ ├── disable_arp.sh │ ├── disable_icmp.sh │ ├── disable_ip_forward.sh │ ├── disable_ipv6.sh │ └── disable_offloading.sh └── topo.py ├── 12-nat ├── Makefile ├── arp.c ├── arpcache.c ├── device_internal.c ├── exp-n1.conf ├── exp-n2.conf ├── exp1.conf ├── exp2.conf ├── http_server.py ├── icmp.c ├── include │ ├── arp.h │ ├── arpcache.h │ ├── base.h │ ├── checksum.h │ ├── ether.h │ ├── hash.h │ ├── icmp.h │ ├── ip.h │ ├── list.h │ ├── log.h │ ├── nat.h │ ├── rtable.h │ ├── tcp.h │ └── types.h ├── ip.c ├── ip_base.c ├── main.c ├── nat.c ├── nat_complex_topo.py ├── nat_topo.py ├── rtable.c ├── rtable_internal.c └── scripts │ ├── disable_arp.sh │ ├── disable_icmp.sh │ ├── disable_ip_forward.sh │ ├── disable_ipv6.sh │ └── disable_offloading.sh ├── 13-tcp_stack ├── Makefile ├── arp.c ├── arpcache.c ├── device_internal.c ├── icmp.c ├── include │ ├── arp.h │ ├── arpcache.h │ ├── base.h │ ├── checksum.h │ ├── ether.h │ ├── hash.h │ ├── icmp.h │ ├── ip.h │ ├── list.h │ ├── log.h │ ├── packet.h │ ├── ring_buffer.h │ ├── rtable.h │ ├── synch_wait.h │ ├── tcp.h │ ├── tcp_apps.h │ ├── tcp_hash.h │ ├── tcp_sock.h │ ├── tcp_timer.h │ └── types.h ├── ip.c ├── ip_base.c ├── main.c ├── rtable.c ├── rtable_internal.c ├── scripts │ ├── disable_arp.sh │ ├── disable_icmp.sh │ ├── disable_ip_forward.sh │ ├── disable_ipv6.sh │ ├── disable_offloading.sh │ └── disable_tcp_rst.sh ├── tcp.c ├── tcp_apps.c ├── tcp_in.c ├── tcp_out.c ├── tcp_sock.c ├── tcp_stack.py ├── tcp_timer.c └── tcp_topo.py ├── 15-tcp_stack ├── Makefile ├── arp.c ├── arpcache.c ├── create_randfile.sh ├── device_internal.c ├── icmp.c ├── include │ ├── arp.h │ ├── arpcache.h │ ├── base.h │ ├── checksum.h │ ├── ether.h │ ├── hash.h │ ├── icmp.h │ ├── ip.h │ ├── list.h │ ├── log.h │ ├── packet.h │ ├── ring_buffer.h │ ├── rtable.h │ ├── synch_wait.h │ ├── tcp.h │ ├── tcp_apps.h │ ├── tcp_hash.h │ ├── tcp_sock.h │ ├── tcp_timer.h │ └── types.h ├── ip.c ├── ip_base.c ├── main.c ├── rtable.c ├── rtable_internal.c ├── scripts │ ├── disable_arp.sh │ ├── disable_icmp.sh │ ├── disable_ip_forward.sh │ ├── disable_ipv6.sh │ ├── disable_offloading.sh │ └── disable_tcp_rst.sh ├── tcp.c ├── tcp_apps.c ├── tcp_in.c ├── tcp_out.c ├── tcp_sock.c ├── tcp_stack.py ├── tcp_stack_file.py ├── tcp_timer.c └── tcp_topo.py ├── 16-tcp_stack ├── Makefile ├── arp.c ├── arpcache.c ├── create_randfile.sh ├── device_internal.c ├── icmp.c ├── include │ ├── arp.h │ ├── arpcache.h │ ├── base.h │ ├── checksum.h │ ├── ether.h │ ├── hash.h │ ├── icmp.h │ ├── ip.h │ ├── list.h │ ├── log.h │ ├── packet.h │ ├── ring_buffer.h │ ├── rtable.h │ ├── synch_wait.h │ ├── tcp.h │ ├── tcp_apps.h │ ├── tcp_hash.h │ ├── tcp_sock.h │ ├── tcp_timer.h │ └── types.h ├── ip.c ├── ip_base.c ├── main.c ├── rtable.c ├── rtable_internal.c ├── scripts │ ├── disable_arp.sh │ ├── disable_icmp.sh │ ├── disable_ip_forward.sh │ ├── disable_ipv6.sh │ ├── disable_offloading.sh │ └── disable_tcp_rst.sh ├── tcp.c ├── tcp_apps.c ├── tcp_in.c ├── tcp_out.c ├── tcp_sock.c ├── tcp_stack.py ├── tcp_stack_file.py ├── tcp_timer.c ├── tcp_topo.py └── tcp_topo_loss.py ├── 17-tcp_stack ├── Makefile ├── arp.c ├── arpcache.c ├── create_randfile.sh ├── device_internal.c ├── icmp.c ├── include │ ├── arp.h │ ├── arpcache.h │ ├── base.h │ ├── checksum.h │ ├── ether.h │ ├── hash.h │ ├── icmp.h │ ├── ip.h │ ├── list.h │ ├── log.h │ ├── packet.h │ ├── ring_buffer.h │ ├── rtable.h │ ├── synch_wait.h │ ├── tcp.h │ ├── tcp_apps.h │ ├── tcp_hash.h │ ├── tcp_sock.h │ ├── tcp_timer.h │ └── types.h ├── ip.c ├── ip_base.c ├── main.c ├── rtable.c ├── rtable_internal.c ├── scripts │ ├── disable_arp.sh │ ├── disable_icmp.sh │ ├── disable_ip_forward.sh │ ├── disable_ipv6.sh │ ├── disable_offloading.sh │ └── disable_tcp_rst.sh ├── tcp.c ├── tcp_apps.c ├── tcp_in.c ├── tcp_out.c ├── tcp_sock.c ├── tcp_stack.py ├── tcp_stack_file.py ├── tcp_timer.c ├── tcp_topo.py ├── tcp_topo_bufferbloat.py └── tcp_topo_loss.py ├── 18-http_server_2 ├── Makefile ├── arp.c ├── arpcache.c ├── create_randfile.sh ├── device_internal.c ├── http.h ├── http_server.c ├── http_utils.c ├── icmp.c ├── include │ ├── arp.h │ ├── arpcache.h │ ├── base.h │ ├── checksum.h │ ├── ether.h │ ├── hash.h │ ├── icmp.h │ ├── ip.h │ ├── list.h │ ├── log.h │ ├── packet.h │ ├── ring_buffer.h │ ├── rtable.h │ ├── synch_wait.h │ ├── tcp.h │ ├── tcp_apps.h │ ├── tcp_hash.h │ ├── tcp_sock.h │ ├── tcp_timer.h │ └── types.h ├── ip.c ├── ip_base.c ├── main.c ├── rtable.c ├── rtable_internal.c ├── scripts │ ├── disable_arp.sh │ ├── disable_icmp.sh │ ├── disable_ip_forward.sh │ ├── disable_ipv6.sh │ ├── disable_offloading.sh │ └── disable_tcp_rst.sh ├── tcp.c ├── tcp_apps.c ├── tcp_in.c ├── tcp_out.c ├── tcp_sock.c ├── tcp_stack.py ├── tcp_stack_file.py ├── tcp_timer.c ├── tcp_topo.py └── tcp_topo_loss.py ├── 18-http_server_4 ├── Makefile ├── arp.c ├── arpcache.c ├── create_randfile.sh ├── device_internal.c ├── http-client.c ├── http-server.c ├── icmp.c ├── include │ ├── arp.h │ ├── arpcache.h │ ├── base.h │ ├── checksum.h │ ├── ether.h │ ├── hash.h │ ├── icmp.h │ ├── ip.h │ ├── list.h │ ├── log.h │ ├── packet.h │ ├── ring_buffer.h │ ├── rtable.h │ ├── synch_wait.h │ ├── tcp.h │ ├── tcp_apps.h │ ├── tcp_hash.h │ ├── tcp_sock.h │ ├── tcp_timer.h │ └── types.h ├── ip.c ├── ip_base.c ├── main.c ├── rtable.c ├── rtable_internal.c ├── scripts │ ├── disable_arp.sh │ ├── disable_icmp.sh │ ├── disable_ip_forward.sh │ ├── disable_ipv6.sh │ ├── disable_offloading.sh │ └── disable_tcp_rst.sh ├── tcp.c ├── tcp_in.c ├── tcp_out.c ├── tcp_sock.c ├── tcp_stack.py ├── tcp_stack_file.py ├── tcp_timer.c └── tcp_topo.py ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*/ 3 | !.gitignore 4 | 5 | !*.c 6 | !*.h 7 | !Makefile 8 | !*.py 9 | !*.sh 10 | !*.conf -------------------------------------------------------------------------------- /02-protocol/fct_exp.py: -------------------------------------------------------------------------------- 1 | from mininet.net import Mininet 2 | from mininet.topo import Topo 3 | from mininet.cli import CLI 4 | from mininet.link import TCLink 5 | from mininet.node import OVSBridge 6 | 7 | class MyTopo(Topo): 8 | def build(self): 9 | h1 = self.addHost('h1') 10 | h2 = self.addHost('h2') 11 | self.addLink(h1, h2, bw=1000, delay='100ms') 12 | 13 | topo = MyTopo() 14 | net = Mininet(topo = topo, switch = OVSBridge, link = TCLink, controller=None) 15 | 16 | net.start() 17 | h2 = net.get('h2') 18 | h2.cmd('python2 -m SimpleHTTPServer 80 &') 19 | CLI(net) 20 | h2.cmd('kill %python') 21 | net.stop() 22 | -------------------------------------------------------------------------------- /03-socket/example/Makefile: -------------------------------------------------------------------------------- 1 | all: echo-client echo-server 2 | 3 | echo-client: echo-client.c 4 | gcc -Wall -g echo-client.c -o echo-client 5 | 6 | echo-server: echo-server.c 7 | gcc -Wall -g echo-server.c -o echo-server 8 | 9 | clean: 10 | @rm -f echo-client echo-server 11 | -------------------------------------------------------------------------------- /03-socket/example/echo-client.c: -------------------------------------------------------------------------------- 1 | /* client application */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | int sock; 12 | struct sockaddr_in server; 13 | char message[1000], server_reply[2000]; 14 | 15 | // create socket 16 | sock = socket(AF_INET, SOCK_STREAM, 0); 17 | if (sock == -1) { 18 | printf("create socket failed"); 19 | return -1; 20 | } 21 | printf("socket created"); 22 | 23 | server.sin_addr.s_addr = inet_addr("10.0.0.1"); 24 | server.sin_family = AF_INET; 25 | server.sin_port = htons(12345); 26 | 27 | // connect to server 28 | if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) { 29 | perror("connect failed"); 30 | return 1; 31 | } 32 | 33 | printf("connected\n"); 34 | 35 | while(1) { 36 | printf("enter message : "); 37 | scanf("%s", message); 38 | 39 | // send some data 40 | if (send(sock, message, strlen(message), 0) < 0) { 41 | printf("send failed"); 42 | return 1; 43 | } 44 | 45 | // receive a reply from the server 46 | int len = recv(sock, server_reply, 2000, 0); 47 | if (len < 0) { 48 | printf("recv failed"); 49 | break; 50 | } 51 | server_reply[len] = 0; 52 | 53 | printf("server reply : "); 54 | printf("%s\n", server_reply); 55 | } 56 | 57 | close(sock); 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /03-socket/example/echo-server.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, const char *argv[]) 8 | { 9 | int s, cs; 10 | struct sockaddr_in server, client; 11 | char msg[2000]; 12 | 13 | // create socket 14 | if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 15 | perror("create socket failed"); 16 | return -1; 17 | } 18 | printf("socket created"); 19 | 20 | // prepare the sockaddr_in structure 21 | server.sin_family = AF_INET; 22 | server.sin_addr.s_addr = INADDR_ANY; 23 | server.sin_port = htons(12345); 24 | 25 | // bind 26 | if (bind(s,(struct sockaddr *)&server, sizeof(server)) < 0) { 27 | perror("bind failed"); 28 | return -1; 29 | } 30 | printf("bind done"); 31 | 32 | // listen 33 | listen(s, 3); 34 | printf("waiting for incoming connections..."); 35 | 36 | // accept connection from an incoming client 37 | int c = sizeof(struct sockaddr_in); 38 | if ((cs = accept(s, (struct sockaddr *)&client, (socklen_t *)&c)) < 0) { 39 | perror("accept failed"); 40 | return -1; 41 | } 42 | printf("connection accepted"); 43 | 44 | int msg_len = 0; 45 | // receive a message from client 46 | while ((msg_len = recv(cs, msg, sizeof(msg), 0)) > 0) { 47 | // send the message back to client 48 | write(cs, msg, msg_len); 49 | } 50 | 51 | if (msg_len == 0) { 52 | printf("client disconnected"); 53 | } 54 | else { // msg_len < 0 55 | perror("recv failed"); 56 | return -1; 57 | } 58 | 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /03-socket/simple-http/Makefile: -------------------------------------------------------------------------------- 1 | all: http-client http-server 2 | 3 | http-client: http-client.c 4 | gcc -Wall -g http-client.c -o http-client 5 | 6 | http-server: http-server.c 7 | gcc -Wall -g http-server.c -o http-server -lpthread 8 | 9 | clean: 10 | @rm -f http-client http-server 11 | -------------------------------------------------------------------------------- /03-socket/simple-http/save-http-client.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/UCAS-Network-Lab/4a19a05e39bcc8a1ed4123c03150e344d15c4a31/03-socket/simple-http/save-http-client.c -------------------------------------------------------------------------------- /03-socket/topo.py: -------------------------------------------------------------------------------- 1 | from mininet.net import Mininet 2 | from mininet.cli import CLI 3 | from mininet.link import TCLink 4 | from mininet.topo import Topo 5 | from mininet.node import OVSBridge 6 | 7 | class MyTopo(Topo): 8 | def build(self): 9 | h1 = self.addHost('h1') 10 | h2 = self.addHost('h2') 11 | s1 = self.addSwitch('s1') 12 | 13 | self.addLink(h1, s1, bw=10, delay='10ms') 14 | self.addLink(h2, s1) 15 | 16 | topo = MyTopo() 17 | net = Mininet(topo = topo, switch = OVSBridge, link = TCLink, controller = None) 18 | net.start() 19 | CLI(net) 20 | net.stop() 21 | -------------------------------------------------------------------------------- /04-broadcast/Makefile: -------------------------------------------------------------------------------- 1 | all: hub 2 | 3 | hub: main.c broadcast.c device_internal.c 4 | gcc -Iinclude/ -Wall -g main.c broadcast.c device_internal.c -o hub 5 | 6 | clean: 7 | @rm -f hub 8 | -------------------------------------------------------------------------------- /04-broadcast/broadcast.c: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | #include 3 | 4 | extern ustack_t *instance; 5 | 6 | void broadcast_packet(iface_info_t *iface, const char *packet, int len) 7 | { 8 | // broadcast packet 9 | iface_info_t * one_iface; 10 | list_for_each_entry(one_iface, &instance->iface_list, list) { 11 | if (one_iface->index != iface->index) { 12 | iface_send_packet(one_iface, packet, len); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /04-broadcast/example/list_example.c: -------------------------------------------------------------------------------- 1 | #include "include/list.h" 2 | 3 | #include 4 | #include 5 | 6 | struct listnode { 7 | struct list_head list; 8 | int number; 9 | }; 10 | 11 | void list_example() 12 | { 13 | struct list_head list; 14 | init_list_head(&list); 15 | 16 | for (int i = 0; i < 10; i++) { 17 | struct listnode *node = malloc(sizeof(struct listnode)); 18 | node->number = i; 19 | list_add_tail(&node->list, &list); 20 | } 21 | 22 | fprintf(stdout, "list all numbers:\n"); 23 | struct listnode *entry; 24 | list_for_each_entry(entry, &list, list) { 25 | fprintf(stdout, "%d\n", entry->number); 26 | } 27 | 28 | fprintf(stdout, "list only odd numbers and remove others:\n"); 29 | struct listnode *q; 30 | list_for_each_entry_safe(entry, q, &list, list) { 31 | if (entry->number % 2 == 0) { 32 | list_delete_entry(&entry->list); 33 | free(entry); 34 | } 35 | else { 36 | fprintf(stdout, "%d\n", entry->number); 37 | } 38 | } 39 | } 40 | 41 | void main() 42 | { 43 | list_example(); 44 | } 45 | -------------------------------------------------------------------------------- /04-broadcast/include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE_H__ 2 | #define __BASE_H__ 3 | 4 | #include "types.h" 5 | #include "ether.h" 6 | #include "list.h" 7 | 8 | #include 9 | 10 | typedef struct { 11 | struct list_head iface_list; 12 | int nifs; 13 | struct pollfd *fds; 14 | } ustack_t; 15 | 16 | extern ustack_t *instance; 17 | 18 | typedef struct { 19 | struct list_head list; 20 | 21 | int fd; 22 | int index; 23 | u8 mac[ETH_ALEN]; 24 | char name[16]; 25 | } iface_info_t; 26 | 27 | void init_ustack(); 28 | iface_info_t *fd_to_iface(int fd); 29 | void iface_send_packet(iface_info_t *iface, const char *packet, int len); 30 | 31 | void broadcast_packet(iface_info_t *iface, const char *packet, int len); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /04-broadcast/include/ether.h: -------------------------------------------------------------------------------- 1 | #ifndef __ETHER_H__ 2 | #define __ETHER_H__ 3 | 4 | #include "types.h" 5 | 6 | #define ETH_ALEN 6 7 | #define ETH_FRAME_LEN 1514 8 | 9 | #define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ 10 | #define ETH_P_IP 0x0800 11 | #define ETH_P_ARP 0x0806 12 | 13 | struct ether_header { 14 | u8 ether_dhost[ETH_ALEN]; 15 | u8 ether_shost[ETH_ALEN]; 16 | u16 ether_type; 17 | }; 18 | 19 | #define ETHER_HDR_SIZE sizeof(struct ether_header) 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /04-broadcast/include/headers.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_H__ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /04-broadcast/include/list.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIST_H__ 2 | #define __LIST_H__ 3 | 4 | #include 5 | 6 | struct list_head { 7 | struct list_head *next, *prev; 8 | }; 9 | 10 | #define list_empty(list) ((list)->next == (list)) 11 | 12 | #define list_entry(ptr, type, member) \ 13 | (type *)((char *)ptr - offsetof(type, member)) 14 | 15 | #define list_for_each_entry(pos, head, member) \ 16 | for (pos = list_entry((head)->next, typeof(*pos), member); \ 17 | &pos->member != (head); \ 18 | pos = list_entry(pos->member.next, typeof(*pos), member)) 19 | 20 | #define list_for_each_entry_safe(pos, q, head, member) \ 21 | for (pos = list_entry((head)->next, typeof(*pos), member), \ 22 | q = list_entry(pos->member.next, typeof(*pos), member); \ 23 | &pos->member != (head); \ 24 | pos = q, q = list_entry(pos->member.next, typeof(*q), member)) 25 | 26 | static inline void init_list_head(struct list_head *list) 27 | { 28 | list->next = list->prev = list; 29 | } 30 | 31 | static inline void list_insert(struct list_head *new, 32 | struct list_head *prev, 33 | struct list_head *next) 34 | { 35 | next->prev = new; 36 | prev->next = new; 37 | new->next = next; 38 | new->prev = prev; 39 | } 40 | 41 | static inline void list_delete_entry(struct list_head *entry) 42 | { 43 | entry->next->prev = entry->prev; 44 | entry->prev->next = entry->next; 45 | } 46 | 47 | static inline void list_add_tail(struct list_head *new, struct list_head *head) 48 | { 49 | list_insert(new, head->prev, head); 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /04-broadcast/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // #define LOG_DEBUG 9 | 10 | enum log_level { DEBUG = 0, INFO, WARNING, ERROR }; 11 | 12 | static enum log_level this_log_level = DEBUG; 13 | 14 | static const char *log_level_str[] = { "DEBUG", "INFO", "WARNING", "ERROR" }; 15 | 16 | #ifdef LOG_DEBUG 17 | #define log_it(fmt, level_str, ...) \ 18 | fprintf(stderr, "[%s:%u] %s: " fmt "\n", __FILE__, __LINE__, \ 19 | level_str, ##__VA_ARGS__); 20 | #else 21 | #define log_it(fmt, level_str, ...) \ 22 | fprintf(stderr, "%s: " fmt "\n", level_str, ##__VA_ARGS__); 23 | #endif 24 | 25 | #define log(level, fmt, ...) \ 26 | do { \ 27 | if (level < this_log_level) \ 28 | break; \ 29 | log_it(fmt, log_level_str[level], ##__VA_ARGS__); \ 30 | } while (0) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /04-broadcast/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | 6 | #define DEFAULT_TTL 64 7 | 8 | typedef uint8_t u8; 9 | typedef uint16_t u16; 10 | typedef uint32_t u32; 11 | typedef uint64_t u64; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /04-broadcast/scripts/disable_ipv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w net.ipv6.conf.all.disable_ipv6=1 4 | sysctl -w net.ipv6.conf.default.disable_ipv6=1 5 | -------------------------------------------------------------------------------- /04-broadcast/scripts/disable_offloading.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The virtual NIC does not support "lro rxhash" options. 4 | TOE_OPTIONS="rx tx sg tso ufo gso gro rxvlan txvlan" 5 | 6 | for IFACE in `/sbin/ifconfig | grep '^.*-eth[0-9]' | awk '{print $1}'`; do 7 | echo "Disabling $IFACE ..." 8 | for TOE_OPTION in $TOE_OPTIONS; do 9 | /sbin/ethtool --offload "$IFACE" "$TOE_OPTION" off 10 | done 11 | done 12 | -------------------------------------------------------------------------------- /05-switching/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = switch 2 | 3 | all : $(TARGET) 4 | 5 | CC = gcc 6 | LD = gcc 7 | 8 | CFLAGS = -g -Wall -Iinclude 9 | LDFLAGS = 10 | 11 | LIBS = -lpthread 12 | 13 | SRCS = broadcast.c device_internal.c mac.c main.c 14 | 15 | OBJS = $(patsubst %.c,%.o,$(SRCS)) 16 | 17 | $(OBJS) : %.o : %.c include/*.h 18 | $(CC) -c $(CFLAGS) $< -o $@ 19 | 20 | $(TARGET): $(OBJS) 21 | $(LD) $(LDFLAGS) $(OBJS) -o $(TARGET) $(LIBS) 22 | 23 | clean: 24 | rm -f *.o $(TARGET) 25 | 26 | tags: *.c include/*.h 27 | ctags *.c include/*.h 28 | -------------------------------------------------------------------------------- /05-switching/broadcast.c: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | #include 3 | 4 | extern ustack_t *instance; 5 | 6 | void broadcast_packet(iface_info_t *iface, const char *packet, int len) 7 | { 8 | // broadcast packet 9 | iface_info_t * one_iface; 10 | list_for_each_entry(one_iface, &instance->iface_list, list) { 11 | if (one_iface->index != iface->index) { 12 | iface_send_packet(one_iface, packet, len); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /05-switching/example/pthread_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | pthread_mutex_t output_lock; 7 | 8 | struct thread_arg { 9 | int index; 10 | int duration; 11 | }; 12 | 13 | void *thread(void * _arg) 14 | { 15 | struct thread_arg *arg = _arg; 16 | sleep(arg->duration); 17 | 18 | pthread_mutex_lock(&output_lock); 19 | fprintf(stdout, "Thread %d wakes up after %d seconds.\n", \ 20 | arg->index, arg->duration); 21 | fflush(stdout); 22 | pthread_mutex_unlock(&output_lock); 23 | } 24 | 25 | int main() 26 | { 27 | pthread_t t1, t2; 28 | 29 | struct thread_arg arg1, arg2; 30 | arg1.index = 1; 31 | arg1.duration = rand() % 5; 32 | arg2.index = 2; 33 | arg2.duration = rand() % 5; 34 | 35 | pthread_mutex_init(&output_lock, NULL); 36 | 37 | pthread_create(&t1, NULL, thread, &arg1); 38 | pthread_create(&t2, NULL, thread, &arg2); 39 | 40 | pthread_join(t1, NULL); 41 | pthread_join(t2, NULL); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /05-switching/include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE_H__ 2 | #define __BASE_H__ 3 | 4 | #include "types.h" 5 | #include "ether.h" 6 | #include "list.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | typedef struct { 28 | struct list_head iface_list; // the list of interfaces 29 | int nifs; // number of interfaces 30 | struct pollfd *fds; // structure used to poll packets among 31 | // all the interfaces 32 | } ustack_t; 33 | 34 | extern ustack_t *instance; 35 | 36 | typedef struct { 37 | struct list_head list; // list node used to link all interfaces 38 | 39 | int fd; // file descriptor for receiving & sending 40 | // packets 41 | int index; // the index (unique ID) of this interface 42 | u8 mac[ETH_ALEN]; // mac address of this interface 43 | char name[16]; // name of this interface 44 | } iface_info_t; 45 | 46 | void init_ustack(); 47 | iface_info_t *fd_to_iface(int fd); 48 | void iface_send_packet(iface_info_t *iface, const char *packet, int len); 49 | 50 | void broadcast_packet(iface_info_t *iface, const char *packet, int len); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /05-switching/include/ether.h: -------------------------------------------------------------------------------- 1 | #ifndef __ETHER_H__ 2 | #define __ETHER_H__ 3 | 4 | #include "types.h" 5 | 6 | #define ETH_ALEN 6 // length of mac address 7 | #define ETH_FRAME_LEN 1514 // maximum length of an ethernet frame (packet) 8 | 9 | // protocol format in ethernet header 10 | #define ETH_P_ALL 0x0003 // every packet, only used when tending to receive all packets 11 | #define ETH_P_IP 0x0800 // IP packet 12 | #define ETH_P_ARP 0x0806 // ARP packet 13 | 14 | struct ether_header { 15 | u8 ether_dhost[ETH_ALEN]; // destination mac address 16 | u8 ether_shost[ETH_ALEN]; // source mac address 17 | u16 ether_type; // protocol format 18 | }; 19 | 20 | #define ETHER_HDR_SIZE sizeof(struct ether_header) 21 | 22 | #define ETHER_STRING "%02x:%02x:%02x:%02x:%02x:%02x" 23 | #define ETHER_FMT(m) m[0],m[1],m[2],m[3],m[4],m[5] 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /05-switching/include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __HASH_H__ 2 | #define __HASH_H__ 3 | 4 | #include "types.h" 5 | 6 | #define HASH_8BITS 256 7 | #define HASH_16BITS 65536 8 | 9 | // the simplest hash functions, you can recreate the wheels as you wish 10 | 11 | static inline u8 hash8(char *buf, int len) 12 | { 13 | u8 result = 0; 14 | for (int i = 0; i < len; i++) 15 | result ^= buf[i]; 16 | 17 | return result; 18 | } 19 | 20 | static inline u16 hash16(char *buf, int len) 21 | { 22 | u16 result = 0; 23 | for (int i = 0; i < len / 2 * 2; i += 2) 24 | result ^= *(u16 *)(buf + i); 25 | 26 | if (len % 2) 27 | result ^= (u8)(buf[len-1]); 28 | 29 | return result; 30 | } 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /05-switching/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // #define LOG_DEBUG 9 | 10 | enum log_level { DEBUG = 0, INFO, WARNING, ERROR }; 11 | 12 | static enum log_level this_log_level = WARNING; 13 | 14 | static const char *log_level_str[] = { "DEBUG", "INFO", "WARNING", "ERROR" }; 15 | 16 | #ifdef LOG_DEBUG 17 | #define log_it(fmt, level_str, ...) \ 18 | fprintf(stderr, "[%s:%u] %s: " fmt "\n", __FILE__, __LINE__, \ 19 | level_str, ##__VA_ARGS__) 20 | #else 21 | #define log_it(fmt, level_str, ...) \ 22 | fprintf(stderr, "%s: " fmt "\n", level_str, ##__VA_ARGS__) 23 | #endif 24 | 25 | #define log(level, fmt, ...) \ 26 | do { \ 27 | if (level < this_log_level) \ 28 | break; \ 29 | log_it(fmt, log_level_str[level], ##__VA_ARGS__); \ 30 | } while (0) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /05-switching/include/mac.h: -------------------------------------------------------------------------------- 1 | #ifndef __MAC_H__ 2 | #define __MAC_H__ 3 | 4 | #include "base.h" 5 | #include "hash.h" 6 | #include "list.h" 7 | 8 | #include 9 | #include 10 | 11 | #define MAC_PORT_TIMEOUT 30 12 | 13 | struct mac_port_entry { 14 | struct list_head list; 15 | uint8_t mac[ETH_ALEN]; 16 | iface_info_t *iface; 17 | time_t visited; 18 | }; 19 | 20 | typedef struct mac_port_entry mac_port_entry_t; 21 | 22 | typedef struct { 23 | struct list_head hash_table[HASH_8BITS]; 24 | pthread_mutex_t lock; 25 | pthread_t thread; 26 | } mac_port_map_t; 27 | 28 | void *sweeping_mac_port_thread(void *); 29 | void init_mac_port_table(); 30 | void destory_mac_port_table(); 31 | void dump_mac_port_table(); 32 | iface_info_t *lookup_port(uint8_t mac[ETH_ALEN]); 33 | void insert_mac_port(uint8_t mac[ETH_ALEN], iface_info_t *iface); 34 | int sweep_aged_mac_port_entry(); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /05-switching/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | 6 | typedef uint8_t u8; 7 | typedef uint16_t u16; 8 | typedef uint32_t u32; 9 | typedef uint64_t u64; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /05-switching/include/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_H__ 2 | #define __UTILS_H__ 3 | 4 | #include 5 | #include 6 | 7 | #define exit_if_null(ptr) \ 8 | do { \ 9 | if (!(ptr)) { \ 10 | fprintf(stderr, #ptr " should not be NULL in " __FILE__ ":%d", __LINE__); \ 11 | exit(1); \ 12 | } \ 13 | } while(0) 14 | 15 | static inline void *safe_malloc(int size) 16 | { 17 | void *ptr = malloc(size); 18 | exit_if_null(ptr); 19 | return ptr; 20 | } 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /05-switching/scripts/disable_ipv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w net.ipv6.conf.all.disable_ipv6=1 4 | sysctl -w net.ipv6.conf.default.disable_ipv6=1 5 | -------------------------------------------------------------------------------- /05-switching/scripts/disable_offloading.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The virtual NIC does not support "lro rxhash" options. 4 | TOE_OPTIONS="rx tx sg tso ufo gso gro rxvlan txvlan" 5 | 6 | for IFACE in `/sbin/ifconfig | grep '^.*-eth[0-9]' | awk '{print $1}'`; do 7 | echo "Disabling $IFACE ..." 8 | for TOE_OPTION in $TOE_OPTIONS; do 9 | /sbin/ethtool --offload "$IFACE" "$TOE_OPTION" off 10 | done 11 | done 12 | -------------------------------------------------------------------------------- /06-stp/Makefile: -------------------------------------------------------------------------------- 1 | TARGET := stp 2 | 3 | all : $(TARGET) 4 | 5 | CC = gcc 6 | LD = gcc 7 | 8 | CFLAGS = -g -Wall -Iinclude 9 | LDFLAGS = 10 | 11 | LIBS = -lpthread 12 | 13 | SRCS = stp.c stp_timer.c main.c broadcast.c device_internal.c mac.c 14 | 15 | OBJS = $(patsubst %.c,%.o,$(SRCS)) 16 | 17 | $(OBJS) : %.o : %.c include/*.h 18 | $(CC) -c $(CFLAGS) $< -o $@ 19 | 20 | $(TARGET): $(OBJS) 21 | $(LD) $(LDFLAGS) $(OBJS) -o $(TARGET) $(LIBS) 22 | 23 | clean: 24 | rm -f *.o $(TARGET) 25 | 26 | tags: *.c include/*.h 27 | ctags *.c include/*.h 28 | -------------------------------------------------------------------------------- /06-stp/broadcast.c: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | #include "stp.h" 3 | #include "log.h" 4 | #include 5 | 6 | extern ustack_t *instance; 7 | 8 | void broadcast_packet(iface_info_t *iface, const char *packet, int len) 9 | { 10 | // broadcast packet 11 | iface_info_t * one_iface; 12 | list_for_each_entry(one_iface, &instance->iface_list, list) { 13 | if (one_iface->index != iface->index && iface_stp_enable(one_iface)) { 14 | log(DEBUG, "Send this packet to %s.", one_iface->name); 15 | iface_send_packet(one_iface, packet, len); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /06-stp/include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE_H__ 2 | #define __BASE_H__ 3 | 4 | #include "types.h" 5 | #include "ether.h" 6 | #include "list.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | typedef struct { 28 | struct list_head iface_list; 29 | int nifs; 30 | struct pollfd *fds; 31 | } ustack_t; 32 | 33 | extern ustack_t *instance; 34 | 35 | typedef struct stp_port stp_port_t; 36 | typedef struct { 37 | struct list_head list; 38 | 39 | int fd; 40 | 41 | int index; 42 | u8 mac[ETH_ALEN]; 43 | char name[16]; 44 | 45 | stp_port_t *port; 46 | } iface_info_t; 47 | 48 | void init_ustack(); 49 | iface_info_t *fd_to_iface(int fd); 50 | void iface_send_packet(iface_info_t *iface, const char *packet, int len); 51 | 52 | void broadcast_packet(iface_info_t *iface, const char *packet, int len); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /06-stp/include/ether.h: -------------------------------------------------------------------------------- 1 | #ifndef __ETHER_H__ 2 | #define __ETHER_H__ 3 | 4 | #include "types.h" 5 | 6 | #define ETH_ALEN 6 7 | #define ETH_FRAME_LEN 1514 8 | 9 | #define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ 10 | #define ETH_P_IP 0x0800 11 | #define ETH_P_ARP 0x0806 12 | 13 | struct ether_header { 14 | u8 ether_dhost[ETH_ALEN]; 15 | u8 ether_shost[ETH_ALEN]; 16 | u16 ether_type; 17 | }; 18 | 19 | #define ETHER_HDR_SIZE sizeof(struct ether_header) 20 | 21 | #define ETHER_STRING "%02x:%02x:%02x:%02x:%02x:%02x" 22 | #define ETHER_FMT(m) m[0],m[1],m[2],m[3],m[4],m[5] 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /06-stp/include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __HASH_H__ 2 | #define __HASH_H__ 3 | 4 | #include "types.h" 5 | 6 | #define HASH_8BITS 256 7 | #define HASH_16BITS 65536 8 | 9 | // the simplest hash functions, you can recreate the wheels as you wish 10 | 11 | static inline u8 hash8(char *buf, int len) 12 | { 13 | u8 result = 0; 14 | for (int i = 0; i < len; i++) 15 | result ^= buf[i]; 16 | 17 | return result; 18 | } 19 | 20 | static inline u16 hash16(char *buf, int len) 21 | { 22 | u16 result = 0; 23 | for (int i = 0; i < len / 2 * 2; i += 2) 24 | result ^= *(u16 *)(buf + i); 25 | 26 | if (len % 2) 27 | result ^= (u8)(buf[len-1]); 28 | 29 | return result; 30 | } 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /06-stp/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // #define LOG_DEBUG 9 | 10 | enum log_level { DEBUG = 0, INFO, WARNING, ERROR }; 11 | 12 | static enum log_level this_log_level = INFO; 13 | 14 | static const char *log_level_str[] = { "DEBUG", "INFO", "WARNING", "ERROR" }; 15 | 16 | #ifdef LOG_DEBUG 17 | #define log_it(fmt, level_str, ...) \ 18 | fprintf(stderr, "[%s:%u] %s: " fmt "\n", __FILE__, __LINE__, \ 19 | level_str, ##__VA_ARGS__); 20 | #else 21 | #define log_it(fmt, level_str, ...) \ 22 | fprintf(stderr, "%s: " fmt "\n", level_str, ##__VA_ARGS__); 23 | #endif 24 | 25 | #define log(level, fmt, ...) \ 26 | do { \ 27 | if (level < this_log_level) \ 28 | break; \ 29 | log_it(fmt, log_level_str[level], ##__VA_ARGS__); \ 30 | } while (0) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /06-stp/include/mac.h: -------------------------------------------------------------------------------- 1 | #ifndef __MAC_H__ 2 | #define __MAC_H__ 3 | 4 | #include "base.h" 5 | #include "hash.h" 6 | #include "list.h" 7 | 8 | #include 9 | #include 10 | 11 | #define MAC_PORT_TIMEOUT 30 12 | 13 | struct mac_port_entry { 14 | struct list_head list; 15 | uint8_t mac[ETH_ALEN]; 16 | iface_info_t *iface; 17 | time_t visited; 18 | }; 19 | 20 | typedef struct mac_port_entry mac_port_entry_t; 21 | 22 | typedef struct { 23 | struct list_head hash_table[HASH_8BITS]; 24 | pthread_mutex_t lock; 25 | pthread_t thread; 26 | } mac_port_map_t; 27 | 28 | void *sweeping_mac_port_thread(void *); 29 | void init_mac_port_table(); 30 | void destory_mac_port_table(); 31 | void dump_mac_port_table(); 32 | iface_info_t *lookup_port(uint8_t mac[ETH_ALEN]); 33 | void insert_mac_port(uint8_t mac[ETH_ALEN], iface_info_t *iface); 34 | int sweep_aged_mac_port_entry(); 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /06-stp/include/stp.h: -------------------------------------------------------------------------------- 1 | #ifndef __STP_H__ 2 | #define __STP_H__ 3 | 4 | #include "stp_proto.h" 5 | #include "stp_timer.h" 6 | 7 | #include "base.h" 8 | #include "types.h" 9 | 10 | #define STP_MAX_PORTS 32 11 | 12 | extern const u8 eth_stp_addr[]; 13 | 14 | enum STP_PORT_STATE { ROOT, DESIGNATED, ALTERNATE }; 15 | extern const char *stp_port_state_str[]; 16 | 17 | typedef struct stp stp_t; 18 | struct stp_port { 19 | stp_t *stp; // pointer to stp 20 | 21 | int port_id; // port id 22 | char *port_name; 23 | iface_info_t *iface; 24 | 25 | int path_cost; // cost of this port, always be 1 in this lab 26 | 27 | u64 designated_root; // root switch (the port believes) 28 | u64 designated_switch; // the switch sending this config 29 | int designated_port; // the port sending this config 30 | int designated_cost; // path cost to root on port 31 | }; 32 | 33 | struct stp { 34 | u64 switch_id; 35 | 36 | u64 designated_root; // switch root (it believes) 37 | int root_path_cost; // cost of path to root 38 | stp_port_t *root_port; // lowest cost port to root 39 | 40 | long long int last_tick; // switch timers 41 | 42 | stp_timer_t hello_timer; // hello timer 43 | 44 | // ports 45 | int nports; 46 | stp_port_t ports[STP_MAX_PORTS]; 47 | 48 | pthread_mutex_t lock; 49 | pthread_t timer_thread; 50 | }; 51 | 52 | void stp_init(struct list_head *iface_list); 53 | void stp_destroy(); 54 | 55 | void stp_port_handle_packet(stp_port_t *, char *packet, int pkt_len); 56 | 57 | int iface_stp_enable(iface_info_t *iface); 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /06-stp/include/stp_timer.h: -------------------------------------------------------------------------------- 1 | #ifndef __STP_TIMER_H__ 2 | #define __STP_TIMER_H__ 3 | 4 | #include "types.h" 5 | #include "list.h" 6 | 7 | #include 8 | 9 | typedef void (*timeout_handler)(void *arg); 10 | 11 | typedef struct { 12 | struct list_head list; 13 | bool active; 14 | long long int time; // time when the timer is set active 15 | int timeout; 16 | timeout_handler func; 17 | void *arg; 18 | } stp_timer_t; 19 | 20 | long long int time_tick_now(); 21 | void stp_init_timer(stp_timer_t *timer, \ 22 | int timeout, timeout_handler func, void *arg); 23 | void stp_start_timer(stp_timer_t *timer, long long int time); 24 | void stp_stop_timer(stp_timer_t *timer); 25 | void stp_timer_run_once(long long int now); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /06-stp/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef uint8_t u8; 8 | typedef uint16_t u16; 9 | typedef uint32_t u32; 10 | typedef uint64_t u64; 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /06-stp/include/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_H__ 2 | #define __UTILS_H__ 3 | 4 | #include "types.h" 5 | #include 6 | #include 7 | #include 8 | 9 | #define htonll(x) ((1==htonl(1)) ? (x) : ((u64)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) 10 | #define ntohll(x) htonll(x) 11 | 12 | #define exit_if_null(ptr) \ 13 | do { \ 14 | if (!(ptr)) { \ 15 | fprintf(stderr, #ptr " should not be NULL in " __FILE__ ":%d", __LINE__); \ 16 | exit(1); \ 17 | } \ 18 | } while(0) 19 | 20 | static inline void *safe_malloc(int size) 21 | { 22 | void *ptr = malloc(size); 23 | exit_if_null(ptr); 24 | return ptr; 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /06-stp/scripts/disable_ipv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w net.ipv6.conf.all.disable_ipv6=1 4 | sysctl -w net.ipv6.conf.default.disable_ipv6=1 5 | -------------------------------------------------------------------------------- /06-stp/scripts/disable_offloading.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The virtual NIC does not support "lro rxhash" options. 4 | TOE_OPTIONS="rx tx sg tso ufo gso gro rxvlan txvlan" 5 | 6 | for IFACE in `/sbin/ifconfig | grep '^.*-eth[0-9]' | awk '{print $1}'`; do 7 | echo "Disabling $IFACE ..." 8 | for TOE_OPTION in $TOE_OPTIONS; do 9 | /sbin/ethtool --offload "$IFACE" "$TOE_OPTION" off 10 | done 11 | done 12 | -------------------------------------------------------------------------------- /06-stp/stp_timer.c: -------------------------------------------------------------------------------- 1 | #include "stp_timer.h" 2 | 3 | #include "log.h" 4 | 5 | bool timer_list_initialized = false; 6 | 7 | struct list_head timer_list; 8 | 9 | // one tick is 1/256 second 10 | long long int time_tick_now() 11 | { 12 | struct timeval now; 13 | gettimeofday(&now, NULL); 14 | 15 | return (long long int)(now.tv_sec) * 256 + now.tv_usec * 256 / 1000000; 16 | } 17 | 18 | void stp_init_timer(stp_timer_t *timer, \ 19 | int timeout, timeout_handler func, void *arg) 20 | { 21 | if (!timer_list_initialized) { 22 | init_list_head(&timer_list); 23 | timer_list_initialized = true; 24 | } 25 | 26 | init_list_head(&timer->list); 27 | 28 | timer->active = false; 29 | timer->timeout = timeout; 30 | timer->func = func; 31 | timer->arg = arg; 32 | 33 | list_add_tail(&timer->list, &timer_list); 34 | } 35 | 36 | void stp_start_timer(stp_timer_t *timer, long long int time) 37 | { 38 | timer->active = true; 39 | timer->time = time; 40 | } 41 | 42 | void stp_stop_timer(stp_timer_t *timer) 43 | { 44 | timer->active = false; 45 | } 46 | 47 | bool stp_check_timer(stp_timer_t *timer, long long int now) 48 | { 49 | if (timer->active) { 50 | if (now >= timer->time + timer->timeout) { 51 | timer->active = false; 52 | return true; 53 | } 54 | } 55 | return false; 56 | } 57 | 58 | void stp_timer_run_once(long long int now) 59 | { 60 | if (!timer_list_initialized) { 61 | log(ERROR, "no timer in the list."); 62 | return ; 63 | } 64 | 65 | stp_timer_t *timer; 66 | list_for_each_entry(timer, &timer_list, list) { 67 | if (stp_check_timer(timer, now)) 68 | timer->func(timer->arg); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /07-bufferbloat/mitigate_bufferbloat.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from mininet.topo import Topo 4 | from mininet.node import Host 5 | from mininet.link import TCLink 6 | from mininet.net import Mininet 7 | from mininet.cli import CLI 8 | 9 | from argparse import ArgumentParser 10 | from utils import * 11 | 12 | import os 13 | 14 | # available algo: taildrop, red, codel 15 | parser = ArgumentParser(description='Args for mitigating Bufferbloat') 16 | parser.add_argument('--algo', '-a', help='Queue discipline algorithm ', required=True) 17 | args = parser.parse_args() 18 | 19 | class BBTopo(Topo): 20 | def build(self): 21 | h1 = self.addHost('h1') 22 | h2 = self.addHost('h2') 23 | r1 = self.addHost('r1') 24 | self.addLink(h1, r1, bw=100, max_queue_size=1000) 25 | self.addLink(h2, r1, bw=100) 26 | 27 | def mitigate_bufferbloat(net, duration=60): 28 | set_qdisc_algo(net, args.algo) 29 | 30 | dname = args.algo 31 | if not os.path.exists(dname): 32 | os.makedirs(dname) 33 | 34 | start_iperf(net, duration, '%s/iperf.txt' % (dname)) 35 | rmon = start_rtt_monitor(net, '%s/rtt.txt' % (dname)) 36 | 37 | dynamic_bw(net, duration) 38 | 39 | stop_rtt_monitor(rmon) 40 | stop_iperf() 41 | 42 | if __name__ == '__main__': 43 | os.system('sysctl -w net.ipv4.tcp_congestion_control=reno') 44 | topo = BBTopo() 45 | net = Mininet(topo=topo, link=TCLink, controller=None) 46 | config_ip(net) 47 | 48 | net.start() 49 | 50 | # CLI(net) 51 | mitigate_bufferbloat(net, 300) 52 | 53 | net.stop() 54 | -------------------------------------------------------------------------------- /07-bufferbloat/produce_iperf_data.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import re 4 | 5 | qlen_list = [10, 50, 100, 150, 200] 6 | # qlen_list = [100] 7 | 8 | pat = re.compile(r'([\d.]+)-.*\s([\d.]+) M?bits/sec') 9 | 10 | for qlen in qlen_list: 11 | input_file_name = 'qlen-%d/iperf.txt.1' % (qlen) 12 | output_file_name = 'qlen-%d/iperf.1.csv' % (qlen) 13 | 14 | with open(input_file_name, "r") as input_file, open(output_file_name, "w") as output_file: 15 | for line in input_file: 16 | matches = pat.findall(line) 17 | if len(matches) > 0: 18 | for cell in matches[0]: 19 | # print(cell) 20 | output_file.write('%s, ' % (cell)) 21 | output_file.write('\n') 22 | 23 | print("Finished %s" % output_file_name) 24 | 25 | -------------------------------------------------------------------------------- /09-router/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = router 2 | 3 | all: $(TARGET) 4 | 5 | CC = gcc 6 | LD = gcc 7 | 8 | CFLAGS = -g -Wall -Iinclude 9 | LDFLAGS = -L. 10 | 11 | LIBS = -lipstack -lpthread 12 | 13 | LIBIP = libipstack.a 14 | LIBIP_SRCS = arp.c arpcache.c icmp.c ip_base.c rtable.c rtable_internal.c device_internal.c 15 | LIBIP_OBJS = $(patsubst %.c,%.o,$(LIBIP_SRCS)) 16 | 17 | HDRS = ./include/*.h 18 | 19 | $(LIBIP_OBJS) : %.o : %.c include/*.h 20 | $(CC) -c $(CFLAGS) $< -o $@ 21 | 22 | $(LIBIP): $(LIBIP_OBJS) 23 | ar rcs $(LIBIP) $(LIBIP_OBJS) 24 | 25 | SRCS = main.c ip.c 26 | OBJS = $(patsubst %.c,%.o,$(SRCS)) 27 | 28 | $(OBJS) : %.o : %.c include/*.h 29 | $(CC) -c $(CFLAGS) $< -o $@ 30 | 31 | $(TARGET): $(LIBIP) $(OBJS) 32 | $(LD) $(LDFLAGS) $(OBJS) -o $(TARGET) $(LIBS) 33 | 34 | clean: 35 | rm -f *.o $(TARGET) $(LIBIP) 36 | 37 | tags: $(SRCS) $(HDRS) 38 | ctags $(SRCS) $(HDRS) 39 | -------------------------------------------------------------------------------- /09-router/include/arp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARP_H__ 2 | #define __ARP_H__ 3 | 4 | #include "base.h" 5 | #include "ether.h" 6 | #include "types.h" 7 | 8 | #define ARPHRD_ETHER 1 9 | 10 | #define ARPOP_REQUEST 1 11 | #define ARPOP_REPLY 2 12 | 13 | struct ether_arp { 14 | u16 arp_hrd; /* Format of hardware address. */ 15 | u16 arp_pro; /* Format of protocol address. */ 16 | u8 arp_hln; /* Length of hardware address. */ 17 | u8 arp_pln; /* Length of protocol address. */ 18 | u16 arp_op; /* ARP opcode (command). */ 19 | u8 arp_sha[ETH_ALEN]; /* sender hardware address */ 20 | u32 arp_spa; /* sender protocol address */ 21 | u8 arp_tha[ETH_ALEN]; /* target hardware address */ 22 | u32 arp_tpa; /* target protocol address */ 23 | } __attribute__ ((packed)); 24 | 25 | #define ETHER_ARP_SIZE sizeof(struct ether_arp) 26 | 27 | void handle_arp_packet(iface_info_t *info, char *pkt, int len); 28 | void arp_send_request(iface_info_t *iface, u32 dst_ip); 29 | void iface_send_packet_by_arp(iface_info_t *iface, u32 dst_ip, char *pkt, int len); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /09-router/include/arpcache.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARPCACHE_H__ 2 | #define __ARPCACHE_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | #include "list.h" 7 | 8 | #include 9 | 10 | #define MAX_ARP_SIZE 32 11 | #define ARP_ENTRY_TIMEOUT 15 12 | #define ARP_REQUEST_MAX_RETRIES 5 13 | 14 | struct cached_pkt { 15 | struct list_head list; 16 | char *packet; 17 | int len; 18 | }; 19 | 20 | struct arp_req { 21 | struct list_head list; 22 | iface_info_t *iface; 23 | u32 ip4; 24 | time_t sent; 25 | int retries; 26 | struct list_head cached_packets; 27 | }; 28 | 29 | struct arp_cache_entry { 30 | u32 ip4; // stored in host byte order 31 | u8 mac[ETH_ALEN]; 32 | time_t added; 33 | int valid; 34 | }; 35 | 36 | typedef struct { 37 | struct arp_cache_entry entries[MAX_ARP_SIZE]; 38 | struct list_head req_list; 39 | pthread_mutex_t lock; 40 | pthread_t thread; 41 | } arpcache_t; 42 | 43 | void arpcache_init(); 44 | void arpcache_destroy(); 45 | void *arpcache_sweep(void *); 46 | 47 | int arpcache_lookup(u32 ip4, u8 mac[]); 48 | void arpcache_insert(u32 ip4, u8 mac[]); 49 | void arpcache_append_packet(iface_info_t *iface, u32 ip4, char *packet, int len); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /09-router/include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE_H__ 2 | #define __BASE_H__ 3 | 4 | #include "types.h" 5 | #include "ether.h" 6 | #include "list.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | typedef struct { 28 | struct list_head iface_list; // the list of interfaces 29 | int nifs; // number of interfaces 30 | struct pollfd *fds; // structure used to poll packets among 31 | // all the interfaces 32 | } ustack_t; 33 | 34 | extern ustack_t *instance; 35 | 36 | typedef struct { 37 | struct list_head list; // list node used to link all interfaces 38 | 39 | int fd; // file descriptor for receiving & sending packets 40 | int index; // the index (unique ID) of this interface 41 | u8 mac[ETH_ALEN]; // mac address of this interface 42 | u32 ip; // IPv4 address (in host byte order) 43 | u32 mask; // Network Mask (in host byte order) 44 | char name[16]; // name of this interface 45 | char ip_str[16]; // readable IP address 46 | } iface_info_t; 47 | 48 | void init_ustack(); 49 | iface_info_t *fd_to_iface(int fd); 50 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 51 | #endif 52 | -------------------------------------------------------------------------------- /09-router/include/checksum.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHECKSUM_H__ 2 | #define __CHECKSUM_H__ 3 | 4 | #include "types.h" 5 | 6 | // calculate the checksum of the given buf, providing sum 7 | // as the initial value 8 | static inline u16 checksum(void *t_ptr, int nbytes, u32 sum) 9 | { 10 | u16 * ptr = t_ptr; 11 | if (nbytes % 2) { 12 | sum += ((u8 *)ptr)[--nbytes]; 13 | } 14 | 15 | while (nbytes > 0) { 16 | sum += *ptr++; 17 | nbytes -= 2; 18 | } 19 | 20 | sum = (sum >> 16) + (sum & 0xffff); 21 | sum = sum + (sum >> 16); 22 | 23 | return (u16)~sum; 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /09-router/include/ether.h: -------------------------------------------------------------------------------- 1 | #ifndef __ETHER_H__ 2 | #define __ETHER_H__ 3 | 4 | #include "types.h" 5 | 6 | #define ETH_ALEN 6 7 | #define ETH_FRAME_LEN 1514 8 | 9 | #define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ 10 | #define ETH_P_IP 0x0800 11 | #define ETH_P_ARP 0x0806 12 | 13 | struct ether_header { 14 | u8 ether_dhost[ETH_ALEN]; 15 | u8 ether_shost[ETH_ALEN]; 16 | u16 ether_type; 17 | }; 18 | 19 | #define ETHER_HDR_SIZE sizeof(struct ether_header) 20 | 21 | #define ETHER_STRING "%02x:%02x:%02x:%02x:%02x:%02x" 22 | #define ETHER_FMT(m) m[0],m[1],m[2],m[3],m[4],m[5] 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /09-router/include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __HASH_H__ 2 | #define __HASH_H__ 3 | 4 | #include "types.h" 5 | 6 | #define HASH_8BITS 256 7 | #define HASH_16BITS 65536 8 | 9 | static inline u8 hash8(char *addr, int len) 10 | { 11 | u8 result = 0; 12 | while (len >= 0) { 13 | result ^= addr[--len]; 14 | } 15 | 16 | return result; 17 | } 18 | 19 | static inline u16 hash16(char *addr, int len) 20 | { 21 | u16 result = 0; 22 | while (len >= 2) { 23 | result ^= *(u8 *)(addr + len - 2); 24 | len -= 2; 25 | } 26 | 27 | if (len) 28 | result ^= (u8)(*addr); 29 | 30 | return result; 31 | } 32 | 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /09-router/include/icmp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ICMP_H__ 2 | #define __ICMP_H__ 3 | 4 | #include "types.h" 5 | #include "checksum.h" 6 | #include "base.h" 7 | 8 | struct icmphdr { 9 | u8 type; 10 | u8 code; 11 | u16 checksum; 12 | union { 13 | struct { 14 | u16 identifier; 15 | u16 sequence; 16 | } is; 17 | struct { 18 | u16 unused; 19 | u16 mtu; 20 | } um; 21 | } u; 22 | #define icmp_identifier u.is.identifier 23 | #define icmp_sequence u.is.sequence 24 | #define icmp_mtu u.um.mtu 25 | }__attribute__((packed)); 26 | 27 | #define ICMP_HDR_SIZE sizeof(struct icmphdr) 28 | #define ICMP_COPIED_DATA_LEN 8 29 | 30 | #define ICMP_ECHOREQUEST 8 /* Echo Request */ 31 | #define ICMP_ECHOREPLY 0 /* Echo Reply */ 32 | #define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ 33 | #define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ 34 | 35 | /* Codes for UNREACH. */ 36 | #define ICMP_NET_UNREACH 0 /* Network Unreachable */ 37 | #define ICMP_HOST_UNREACH 1 /* Host Unreachable */ 38 | #define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ 39 | #define ICMP_PORT_UNREACH 3 /* Port Unreachable */ 40 | 41 | /* Codes for TIME_EXCEEDED. */ 42 | #define ICMP_EXC_TTL 0 /* TTL count exceeded */ 43 | 44 | static inline u16 icmp_checksum(struct icmphdr *icmp, int len) 45 | { 46 | u16 tmp = icmp->checksum; 47 | icmp->checksum = 0; 48 | u16 sum = checksum((u16 *)icmp, len, 0); 49 | icmp->checksum = tmp; 50 | 51 | return sum; 52 | } 53 | 54 | void icmp_send_packet(const char *in_pkt, int len, u8 type, u8 code); 55 | void handle_icmp_packet(char *packet, int len); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /09-router/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // #define LOG_DEBUG 9 | 10 | enum log_level { DEBUG = 0, INFO, WARNING, ERROR }; 11 | 12 | static enum log_level this_log_level = DEBUG; 13 | 14 | static const char *log_level_str[] = { "DEBUG", "INFO", "WARNING", "ERROR" }; 15 | 16 | #ifdef LOG_DEBUG 17 | #define log_it(fmt, level_str, ...) \ 18 | fprintf(stderr, "[%s:%u] %s: " fmt "\n", __FILE__, __LINE__, \ 19 | level_str, ##__VA_ARGS__); 20 | #else 21 | #define log_it(fmt, level_str, ...) \ 22 | fprintf(stderr, "%s: " fmt "\n", level_str, ##__VA_ARGS__); 23 | #endif 24 | 25 | #define log(level, fmt, ...) \ 26 | do { \ 27 | if (level < this_log_level) \ 28 | break; \ 29 | log_it(fmt, log_level_str[level], ##__VA_ARGS__); \ 30 | } while (0) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /09-router/include/rtable.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTABLE_H__ 2 | #define __RTABLE_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | #include "list.h" 8 | 9 | // structure of ip forwarding table 10 | // note: 1, the table supports only ipv4 address; 11 | // 2, addresses are stored in host byte order. 12 | typedef struct { 13 | struct list_head list; 14 | u32 dest; // destination ip address (could be network or host) 15 | u32 mask; // network mask of dest 16 | u32 gw; // ip address of next hop (will be 0 if dest is in 17 | // the same network with iface) 18 | int flags; // flags (could be omitted here) 19 | char if_name[16]; // name of the interface 20 | iface_info_t *iface; // pointer to the interface structure 21 | } rt_entry_t; 22 | 23 | extern struct list_head rtable; 24 | 25 | void init_rtable(); 26 | void load_static_rtable(); 27 | void clear_rtable(); 28 | void add_rt_entry(rt_entry_t *entry); 29 | void remove_rt_entry(rt_entry_t *entry); 30 | void print_rtable(); 31 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface); 32 | 33 | rt_entry_t *longest_prefix_match(u32 ip); 34 | 35 | void load_rtable_from_kernel(); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /09-router/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | 6 | #define NET_CONST_MTU 1500 7 | 8 | #define DEFAULT_TTL 64 9 | 10 | typedef uint8_t u8; 11 | typedef uint16_t u16; 12 | typedef uint32_t u32; 13 | typedef uint64_t u64; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /09-router/include/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_H__ 2 | #define __UTILS_H__ 3 | 4 | #include 5 | #include 6 | 7 | #define exit_if_null(ptr) \ 8 | do { \ 9 | if (!(ptr)) { \ 10 | fprintf(stderr, #ptr " should not be NULL in " __FILE__ ":%d", __LINE__); \ 11 | exit(1); \ 12 | } \ 13 | } while(0) 14 | 15 | static inline void *safe_malloc(int size) 16 | { 17 | void *ptr = malloc(size); 18 | exit_if_null(ptr); 19 | return ptr; 20 | } 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /09-router/rtable.c: -------------------------------------------------------------------------------- 1 | #include "rtable.h" 2 | #include "ip.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct list_head rtable; 9 | 10 | void init_rtable() 11 | { 12 | init_list_head(&rtable); 13 | } 14 | 15 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface) 16 | { 17 | rt_entry_t *entry = malloc(sizeof(*entry)); 18 | memset(entry, 0, sizeof(*entry)); 19 | 20 | init_list_head(&(entry->list)); 21 | entry->dest = dest; 22 | entry->mask = mask; 23 | entry->gw = gw; 24 | entry->iface = iface; 25 | strcpy(entry->if_name, iface->name); 26 | 27 | return entry; 28 | } 29 | 30 | void add_rt_entry(rt_entry_t *entry) 31 | { 32 | list_add_tail(&entry->list, &rtable); 33 | } 34 | 35 | void remove_rt_entry(rt_entry_t *entry) 36 | { 37 | list_delete_entry(&entry->list); 38 | free(entry); 39 | } 40 | 41 | void clear_rtable() 42 | { 43 | struct list_head *head = &rtable, *tmp; 44 | while (head->next != head) { 45 | tmp = head->next; 46 | list_delete_entry(tmp); 47 | rt_entry_t *entry = list_entry(tmp, rt_entry_t, list); 48 | free(entry); 49 | } 50 | } 51 | 52 | void print_rtable() 53 | { 54 | // Print the route records 55 | fprintf(stdout, "Routing Table:\n"); 56 | fprintf(stdout, "dest\tmask\tgateway\tif_name\n"); 57 | fprintf(stdout, "--------------------------------------\n"); 58 | rt_entry_t *entry = NULL; 59 | list_for_each_entry(entry, &rtable, list) { 60 | fprintf(stdout, IP_FMT"\t"IP_FMT"\t"IP_FMT"\t%s\n", \ 61 | HOST_IP_FMT_STR(entry->dest), \ 62 | HOST_IP_FMT_STR(entry->mask), \ 63 | HOST_IP_FMT_STR(entry->gw), \ 64 | entry->if_name); 65 | } 66 | fprintf(stdout, "--------------------------------------\n"); 67 | } 68 | -------------------------------------------------------------------------------- /09-router/scripts/disable_arp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | arptables -A FORWARD -j DROP 4 | arptables -A OUTPUT -j DROP 5 | -------------------------------------------------------------------------------- /09-router/scripts/disable_icmp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p icmp --icmp-type echo-request -j DROP 4 | iptables -A OUTPUT -p icmp --icmp-type echo-reply -j DROP 5 | iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP 6 | -------------------------------------------------------------------------------- /09-router/scripts/disable_ip_forward.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # iptables -A INPUT -p ip -j DROP 4 | echo 0 > /proc/sys/net/ipv4/ip_forward 5 | -------------------------------------------------------------------------------- /09-router/scripts/disable_ipv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w net.ipv6.conf.all.disable_ipv6=1 4 | sysctl -w net.ipv6.conf.default.disable_ipv6=1 5 | -------------------------------------------------------------------------------- /09-router/scripts/disable_offloading.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The virtual NIC does not support "lro rxhash" options. 4 | TOE_OPTIONS="rx tx sg tso ufo gso gro rxvlan txvlan" 5 | 6 | for IFACE in `/sbin/ifconfig | grep '^.*-eth[0-9]' | awk '{print $1}'`; do 7 | echo "Disabling $IFACE ..." 8 | for TOE_OPTION in $TOE_OPTIONS; do 9 | /sbin/ethtool --offload "$IFACE" "$TOE_OPTION" off 10 | done 11 | done 12 | -------------------------------------------------------------------------------- /10-lookup/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = main 2 | 3 | all: $(TARGET) 4 | 5 | CC = gcc 6 | LD = gcc 7 | 8 | CFLAGS = -g -Wall -Iinclude -O2 9 | LDFLAGS = -L. 10 | 11 | LIBS = 12 | 13 | HDRS = ./include/*.h 14 | 15 | SRCS = main.c trie.c 16 | OBJS = $(patsubst %.c,%.o,$(SRCS)) 17 | 18 | $(OBJS) : %.o : %.c include/*.h 19 | $(CC) -c $(CFLAGS) $< -o $@ 20 | 21 | $(TARGET): $(OBJS) 22 | $(LD) $(LDFLAGS) $(OBJS) -o $(TARGET) $(LIBS) 23 | 24 | clean: 25 | rm -f *.o $(TARGET) $(LIBIP) 26 | 27 | tags: $(SRCS) $(HDRS) 28 | ctags $(SRCS) $(HDRS) 29 | -------------------------------------------------------------------------------- /10-lookup/include/binary.h: -------------------------------------------------------------------------------- 1 | #ifndef __BINARY_H__ 2 | #define __BINARY_H__ 3 | 4 | #define ALL_ONE ( ~ 0U ) 5 | 6 | #define PREFIX_ZERO(i) ( (i) >= 32 ? 0U : (ALL_ONE >> (i)) ) 7 | #define PREFIX_ONE(i) ( ~ PREFIX_ZERO(i) ) 8 | 9 | #define SUFFIX_ZERO(i) ( (i) >= 32 ? 0U : (ALL_ONE << (i)) ) 10 | #define SUFFIX_ONE(i) ( ~ SUFFIX_ZERO(i) ) 11 | 12 | #define PREFIX_OF(n, i) ( n & PREFIX_ONE(i) ) 13 | #define SUFFIX_OF(n, i) ( n & SUFFIX_ONE(i) ) 14 | 15 | #define I_BIT(i) ( 1U << (i) ) 16 | #define BIT_OF(n, i) ( ((unsigned)(n) >> (i)) & 1U ) 17 | 18 | #endif -------------------------------------------------------------------------------- /10-lookup/include/ip.h: -------------------------------------------------------------------------------- 1 | #ifndef __IP_H__ 2 | #define __IP_H__ 3 | 4 | #include 5 | 6 | #define IP_FMT "%hhu.%hhu.%hhu.%hhu" 7 | #define IP_FMT_STR(ip) ((uint8_t *)&(ip))[3], \ 8 | ((uint8_t *)&(ip))[2], \ 9 | ((uint8_t *)&(ip))[1], \ 10 | ((uint8_t *)&(ip))[0] 11 | 12 | #define IP_SCAN_STR(ip) ((uint8_t *)&(ip) + 3), \ 13 | ((uint8_t *)&(ip) + 2), \ 14 | ((uint8_t *)&(ip) + 1), \ 15 | ((uint8_t *)&(ip) + 0) 16 | 17 | #endif -------------------------------------------------------------------------------- /10-lookup/include/trie.h: -------------------------------------------------------------------------------- 1 | #ifndef __TRIE_H__ 2 | #define __TRIE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | extern size_t memory_measure; 9 | 10 | struct TrieNode { 11 | // struct TrieNode * parent; // for struct changing 12 | struct TrieNode * children[2]; 13 | 14 | // route info 15 | uint32_t ip; 16 | uint32_t prefix; 17 | bool match; 18 | int port; 19 | }; 20 | 21 | struct TrieNode * trie_init(); 22 | int trie_lookup(struct TrieNode * root, uint32_t ip); 23 | void trie_insert(struct TrieNode * root, uint32_t ip, uint32_t prefix, int port); 24 | void trie_insert_compress(struct TrieNode * root, uint32_t ip, uint32_t prefix, int port); 25 | 26 | void print_trie(struct TrieNode * root); 27 | 28 | #endif -------------------------------------------------------------------------------- /10-lookup/test.sh: -------------------------------------------------------------------------------- 1 | # ./main 1 forwarding-table.txt >tree_basic.txt # get tree of basic trie 2 | # ./main 9 forwarding-table.txt >tree_compress.txt # get tree of compress trie 3 | 4 | # ./main 10 forwarding-table.txt >port_compress.txt # get lookup result of basic trie 5 | # ./main 2 forwarding-table.txt >port_basic.txt # get lookup result of port trie 6 | 7 | ./main 12 forwarding-table.txt >res_compress.txt # get time & mem result of basic trie 8 | ./main 4 forwarding-table.txt >res_basic.txt # get time & mem result of port trie 9 | -------------------------------------------------------------------------------- /11-mopsf/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = mospfd 2 | 3 | all: $(TARGET) 4 | 5 | CC = gcc 6 | LD = gcc 7 | 8 | CFLAGS = -g -Wall -Wno-unused-variable -Wno-unused-function -Iinclude 9 | LDFLAGS = -L. 10 | 11 | LIBS = -lpthread 12 | 13 | HDRS = ./include/*.h 14 | 15 | SRCS = arp.c arpcache.c device_internal.c icmp.c ip_base.c ip.c main.c mospf_database.c mospf_daemon.c mospf_proto.c mospf_nbr.c mospf_route.c rtable.c rtable_internal.c 16 | OBJS = $(patsubst %.c,%.o,$(SRCS)) 17 | 18 | $(OBJS) : %.o : %.c include/*.h 19 | $(CC) -c $(CFLAGS) $< -o $@ 20 | 21 | $(TARGET): $(LIBIP) $(OBJS) 22 | $(LD) $(LDFLAGS) $(OBJS) -o $(TARGET) $(LIBS) 23 | 24 | clean: 25 | rm -f *.o $(TARGET) 26 | -------------------------------------------------------------------------------- /11-mopsf/include/arp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARP_H__ 2 | #define __ARP_H__ 3 | 4 | #include "base.h" 5 | #include "ether.h" 6 | #include "types.h" 7 | 8 | #define ARPHRD_ETHER 1 9 | 10 | #define ARPOP_REQUEST 1 11 | #define ARPOP_REPLY 2 12 | 13 | struct ether_arp { 14 | u16 arp_hrd; // format of hardware address, should be 0x01 15 | u16 arp_pro; // format of protocol address, should be 0x0800 16 | u8 arp_hln; // length of hardware address, should be 6 17 | u8 arp_pln; // length of protocol address, should be 4 18 | u16 arp_op; // ARP opcode (command) 19 | u8 arp_sha[ETH_ALEN]; // sender hardware address 20 | u32 arp_spa; // sender protocol address 21 | u8 arp_tha[ETH_ALEN]; // target hardware address 22 | u32 arp_tpa; // target protocol address 23 | } __attribute__ ((packed)); 24 | 25 | // get the arp header of the packet 26 | static inline struct ether_arp *packet_to_ether_arp(const char *packet) 27 | { 28 | return (struct ether_arp *)(packet + ETHER_HDR_SIZE); 29 | } 30 | 31 | void handle_arp_packet(iface_info_t *info, char *packet, int len); 32 | void arp_send_request(iface_info_t *iface, u32 dst_ip); 33 | void iface_send_packet_by_arp(iface_info_t *iface, u32 dst_ip, char *packet, int len); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /11-mopsf/include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE_H__ 2 | #define __BASE_H__ 3 | 4 | #include "types.h" 5 | #include "ether.h" 6 | #include "list.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #define DYNAMIC_ROUTING 28 | 29 | typedef struct { 30 | struct list_head iface_list; // the list of interfaces 31 | int nifs; // number of interfaces 32 | struct pollfd *fds; // structure used to poll packets among 33 | // all the interfaces 34 | 35 | #ifdef DYNAMIC_ROUTING 36 | // used for mospf routing 37 | u32 area_id; 38 | u32 router_id; 39 | u16 sequence_num; 40 | int lsuint; 41 | #endif 42 | } ustack_t; 43 | 44 | extern ustack_t *instance; 45 | 46 | typedef struct { 47 | struct list_head list; // list node used to link all interfaces 48 | 49 | int fd; // file descriptor for receiving & sending packets 50 | int index; // the index (unique ID) of this interface 51 | u8 mac[ETH_ALEN]; // mac address of this interface 52 | u32 ip; // IPv4 address (in host byte order) 53 | u32 mask; // Network Mask (in host byte order) 54 | char name[16]; // name of this interface 55 | char ip_str[16]; // readable IP address 56 | 57 | #ifdef DYNAMIC_ROUTING 58 | // list of mospf neighbors 59 | int helloint; 60 | int num_nbr; 61 | struct list_head nbr_list; 62 | #endif 63 | } iface_info_t; 64 | 65 | void init_ustack(); 66 | iface_info_t *fd_to_iface(int fd); 67 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 68 | #endif 69 | -------------------------------------------------------------------------------- /11-mopsf/include/checksum.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHECKSUM_H__ 2 | #define __CHECKSUM_H__ 3 | 4 | #include "types.h" 5 | 6 | // calculate the checksum of the given buf, providing sum 7 | // as the initial value 8 | static inline u16 checksum(void *t_buf, int nbytes, u32 sum) 9 | { 10 | u16 * buf = t_buf; 11 | for (int i = 0; i < nbytes / 2; i++) 12 | sum += buf[i]; 13 | 14 | sum = (sum >> 16) + (sum & 0xffff); 15 | sum = sum + (sum >> 16); 16 | 17 | if (nbytes % 2) 18 | sum += ((u8 *)buf)[nbytes-1]; 19 | 20 | return (u16)~sum; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /11-mopsf/include/ether.h: -------------------------------------------------------------------------------- 1 | #ifndef __ETHER_H__ 2 | #define __ETHER_H__ 3 | 4 | #include "types.h" 5 | 6 | #define ETH_ALEN 6 // length of mac address 7 | #define ETH_FRAME_LEN 1514 // maximum length of an ethernet frame (packet) 8 | 9 | // protocol format in ethernet header 10 | #define ETH_P_ALL 0x0003 // every packet, only used when tending to receive all packets 11 | #define ETH_P_IP 0x0800 // IP packet 12 | #define ETH_P_ARP 0x0806 // ARP packet 13 | 14 | struct ether_header { 15 | u8 ether_dhost[ETH_ALEN]; // destination mac address 16 | u8 ether_shost[ETH_ALEN]; // source mac address 17 | u16 ether_type; // protocol format 18 | }; 19 | 20 | #define ETHER_HDR_SIZE sizeof(struct ether_header) 21 | 22 | #define ETHER_STRING "%02x:%02x:%02x:%02x:%02x:%02x" 23 | #define ETHER_FMT(m) m[0],m[1],m[2],m[3],m[4],m[5] 24 | 25 | #define mac_assign(d, a0, a1, a2, a3, a4, a5) \ 26 | d[0] = a0, d[1] = a1, d[2] = a2, d[3] = a3, d[4] = a4, d[5] = a5 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /11-mopsf/include/icmp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ICMP_H__ 2 | #define __ICMP_H__ 3 | 4 | #include "types.h" 5 | #include "checksum.h" 6 | #include "base.h" 7 | 8 | struct icmphdr { 9 | u8 type; // type of icmp message 10 | u8 code; // icmp code 11 | u16 checksum; 12 | u16 icmp_identifier; // icmp identifier, used in icmp echo request 13 | u16 icmp_sequence; // icmp sequence, used in icmp echo request 14 | }__attribute__((packed)); 15 | 16 | #define ICMP_HDR_SIZE sizeof(struct icmphdr) 17 | #define ICMP_COPIED_DATA_LEN 8 18 | 19 | #define ICMP_ECHOREQUEST 8 // echo request 20 | #define ICMP_ECHOREPLY 0 // echo reply 21 | #define ICMP_DEST_UNREACH 3 // destination unreachable 22 | #define ICMP_TIME_EXCEEDED 11 // time exceeded 23 | 24 | // codes for UNREACH 25 | #define ICMP_NET_UNREACH 0 // network unreachable 26 | #define ICMP_HOST_UNREACH 1 // host unreachable 27 | 28 | // code for TIME_EXCEEDED 29 | #define ICMP_EXC_TTL 0 // ttl count exceeded 30 | 31 | // calculate the checksum of icmp data, note that the length of icmp data varies 32 | static inline u16 icmp_checksum(struct icmphdr *icmp, int len) 33 | { 34 | u16 tmp = icmp->checksum; 35 | icmp->checksum = 0; 36 | u16 sum = checksum((u16 *)icmp, len, 0); 37 | icmp->checksum = tmp; 38 | 39 | return sum; 40 | } 41 | 42 | // construct icmp packet according to type, code and incoming packet, and send it 43 | void icmp_send_packet(const char *in_pkt, int len, u8 type, u8 code); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /11-mopsf/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // #define LOG_DEBUG 9 | 10 | enum log_level { DEBUG = 0, INFO, WARNING, ERROR }; 11 | 12 | static enum log_level this_log_level = DEBUG; 13 | 14 | static const char *log_level_str[] = { "DEBUG", "INFO", "WARNING", "ERROR" }; 15 | 16 | #ifdef LOG_DEBUG 17 | #define log_it(fmt, level_str, ...) \ 18 | fprintf(stderr, "[%s:%u] %s: " fmt "\n", __FILE__, __LINE__, \ 19 | level_str, ##__VA_ARGS__); 20 | #else 21 | #define log_it(fmt, level_str, ...) \ 22 | fprintf(stdout, "%s: " fmt "\n", level_str, ##__VA_ARGS__); 23 | #endif 24 | 25 | #define log(level, fmt, ...) \ 26 | do { \ 27 | if (level < this_log_level) \ 28 | break; \ 29 | log_it(fmt, log_level_str[level], ##__VA_ARGS__); \ 30 | } while (0) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /11-mopsf/include/mospf_daemon.h: -------------------------------------------------------------------------------- 1 | #ifndef __MOSPF_DAEMON_H__ 2 | #define __MOSPF_DAEMON_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | #include "list.h" 7 | 8 | void mospf_init(); 9 | void mospf_run(); 10 | void handle_mospf_packet(iface_info_t *iface, char *packet, int len); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /11-mopsf/include/mospf_database.h: -------------------------------------------------------------------------------- 1 | #ifndef __MOSPF_DATABASE_H__ 2 | #define __MOSPF_DATABASE_H__ 3 | 4 | #include "base.h" 5 | #include "list.h" 6 | 7 | #include "mospf_proto.h" 8 | 9 | extern struct list_head mospf_db; 10 | extern int mospf_db_cnt; 11 | 12 | typedef struct { 13 | struct list_head list; 14 | u32 rid; 15 | u16 seq; 16 | int nadv; 17 | int alive; 18 | struct mospf_lsa *array; 19 | } mospf_db_entry_t; 20 | 21 | void init_mospf_db(); 22 | int aging_mospf_db(); 23 | int update_mospf_db(const char * mospf_lsu_msg); 24 | void print_mospf_db(); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /11-mopsf/include/mospf_nbr.h: -------------------------------------------------------------------------------- 1 | #ifndef __NOSPF_NBR_H__ 2 | #define __NOSPF_NBR_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | #include "list.h" 7 | 8 | typedef struct { 9 | struct list_head list; 10 | u32 nbr_id; // neighbor ID 11 | u32 nbr_ip; // neighbor IP 12 | u32 nbr_mask; // neighbor mask 13 | u8 alive; // alive for #(seconds) 14 | } mospf_nbr_t; 15 | 16 | int aging_mospf_nbr(); 17 | int update_mospf_nbr(iface_info_t *iface, const char *packet); 18 | 19 | void print_nbr_list(); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /11-mopsf/include/mospf_route.h: -------------------------------------------------------------------------------- 1 | #ifndef __MOSPF_ROUTE_H__ 2 | #define __MOSPF_ROUTE_H__ 3 | 4 | void update_rtable_from_database(); 5 | 6 | #endif -------------------------------------------------------------------------------- /11-mopsf/include/rtable.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTABLE_H__ 2 | #define __RTABLE_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | #include "list.h" 8 | 9 | // structure of ip forwarding table 10 | // note: 1, the table supports only ipv4 address; 11 | // 2, addresses are stored in host byte order. 12 | typedef struct { 13 | struct list_head list; 14 | u32 dest; // destination ip address (could be network or host) 15 | u32 mask; // network mask of dest 16 | u32 gw; // ip address of next hop (will be 0 if dest is in 17 | // the same network with iface) 18 | int flags; // flags (could be omitted here) 19 | char if_name[16]; // name of the interface 20 | iface_info_t *iface; // pointer to the interface structure 21 | } rt_entry_t; 22 | 23 | extern struct list_head rtable; 24 | extern pthread_mutex_t rtable_lock; 25 | 26 | void init_rtable(); 27 | void load_static_rtable(); 28 | void clear_rtable(); 29 | void add_rt_entry(rt_entry_t *entry); 30 | void remove_rt_entry(rt_entry_t *entry); 31 | void print_rtable(); 32 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface); 33 | void try_add_new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface); 34 | 35 | rt_entry_t *longest_prefix_match(u32 ip); 36 | u32 get_next_hop(rt_entry_t *entry, u32 dst); 37 | 38 | void load_rtable_from_kernel(); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /11-mopsf/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | 6 | typedef uint8_t u8; 7 | typedef uint16_t u16; 8 | typedef uint32_t u32; 9 | typedef uint64_t u64; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /11-mopsf/ip.c: -------------------------------------------------------------------------------- 1 | #include "ip.h" 2 | #include "icmp.h" 3 | #include "arpcache.h" 4 | #include "rtable.h" 5 | #include "arp.h" 6 | 7 | #include "mospf_proto.h" 8 | #include "mospf_daemon.h" 9 | 10 | #include "log.h" 11 | 12 | #include 13 | #include 14 | 15 | // handle ip packet 16 | // 17 | // If the packet is ICMP echo request and the destination IP address is equal to 18 | // the IP address of the iface, send ICMP echo reply; otherwise, forward the 19 | // packet. 20 | void handle_ip_packet(iface_info_t *iface, char *packet, int len) 21 | { 22 | struct iphdr *ip = packet_to_ip_hdr(packet); 23 | u32 daddr = ntohl(ip->daddr); 24 | if (daddr == iface->ip) { 25 | if (ip->protocol == IPPROTO_ICMP) { 26 | struct icmphdr *icmp = (struct icmphdr *)IP_DATA(ip); 27 | if (icmp->type == ICMP_ECHOREQUEST) { 28 | icmp_send_packet(packet, len, ICMP_ECHOREPLY, 0); 29 | } 30 | } 31 | else if (ip->protocol == IPPROTO_MOSPF) { 32 | handle_mospf_packet(iface, packet, len); 33 | } 34 | 35 | free(packet); 36 | } 37 | else if (ip->daddr == htonl(MOSPF_ALLSPFRouters)) { 38 | assert(ip->protocol == IPPROTO_MOSPF); 39 | handle_mospf_packet(iface, packet, len); 40 | 41 | free(packet); 42 | } 43 | else { 44 | ip_forward_packet(daddr, packet, len); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /11-mopsf/scripts/disable_arp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | arptables -A FORWARD -j DROP 4 | arptables -A OUTPUT -j DROP 5 | -------------------------------------------------------------------------------- /11-mopsf/scripts/disable_icmp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p icmp --icmp-type echo-request -j DROP 4 | iptables -A OUTPUT -p icmp --icmp-type echo-reply -j DROP 5 | iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP 6 | -------------------------------------------------------------------------------- /11-mopsf/scripts/disable_ip_forward.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # iptables -A INPUT -p ip -j DROP 4 | echo 0 > /proc/sys/net/ipv4/ip_forward 5 | -------------------------------------------------------------------------------- /11-mopsf/scripts/disable_ipv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w net.ipv6.conf.all.disable_ipv6=1 4 | sysctl -w net.ipv6.conf.default.disable_ipv6=1 5 | -------------------------------------------------------------------------------- /11-mopsf/scripts/disable_offloading.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The virtual NIC does not support "lro rxhash" options. 4 | TOE_OPTIONS="rx tx sg tso ufo gso gro rxvlan txvlan" 5 | 6 | for IFACE in `/sbin/ifconfig | grep '^.*-eth[0-9]' | awk '{print $1}'`; do 7 | echo "Disabling $IFACE ..." 8 | for TOE_OPTION in $TOE_OPTIONS; do 9 | /sbin/ethtool --offload "$IFACE" "$TOE_OPTION" off 10 | done 11 | done 12 | -------------------------------------------------------------------------------- /12-nat/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = nat 2 | 3 | all: $(TARGET) 4 | 5 | CC = gcc 6 | LD = gcc 7 | 8 | CFLAGS = -g -Wall -Wno-unused-variable -Wno-unused-function -Iinclude 9 | LDFLAGS = -L. 10 | 11 | LIBS = -lpthread 12 | 13 | HDRS = ./include/*.h 14 | 15 | SRCS = arp.c arpcache.c device_internal.c icmp.c ip_base.c ip.c main.c nat.c rtable.c rtable_internal.c 16 | OBJS = $(patsubst %.c,%.o,$(SRCS)) 17 | 18 | $(OBJS) : %.o : %.c include/*.h 19 | $(CC) -c $(CFLAGS) $< -o $@ 20 | 21 | $(TARGET): $(LIBIP) $(OBJS) 22 | $(LD) $(LDFLAGS) $(OBJS) -o $(TARGET) $(LIBS) 23 | 24 | clean: 25 | rm -f *.o $(TARGET) 26 | -------------------------------------------------------------------------------- /12-nat/exp-n1.conf: -------------------------------------------------------------------------------- 1 | internal-iface: n1-eth0 2 | external-iface: n1-eth1 3 | -------------------------------------------------------------------------------- /12-nat/exp-n2.conf: -------------------------------------------------------------------------------- 1 | internal-iface: n2-eth0 2 | external-iface: n2-eth1 3 | 4 | dnat-rule: 159.226.39.123:8080 -> 10.0.2.22:8000 -------------------------------------------------------------------------------- /12-nat/exp1.conf: -------------------------------------------------------------------------------- 1 | internal-iface: n1-eth0 2 | external-iface: n1-eth1 3 | -------------------------------------------------------------------------------- /12-nat/exp2.conf: -------------------------------------------------------------------------------- 1 | internal-iface: n1-eth0 2 | external-iface: n1-eth1 3 | 4 | dnat-rules: 159.226.39.43:8000 -> 10.21.0.1:8000 5 | dnat-rules: 159.226.39.43:8001 -> 10.21.0.2:8000 6 | -------------------------------------------------------------------------------- /12-nat/http_server.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import socket 4 | import struct 5 | import fcntl 6 | import BaseHTTPServer 7 | 8 | INDEX_PAGE_FMT = ''' 9 | 10 | 11 | 12 | Network IP Address 13 | 14 | 15 | My IP is: my_ip_here 16 | Remote IP is: your_ip_here 17 | 18 | 19 | ''' 20 | 21 | def my_ip(): 22 | intfs = os.listdir('/sys/class/net/') 23 | intfs.remove('lo') 24 | if len(intfs) == 0: 25 | return 'N/A' 26 | SIOCGIFADDR = 0x8915 27 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 28 | return socket.inet_ntoa(fcntl.ioctl(s.fileno(), SIOCGIFADDR, struct.pack('256s', intfs[0][:15]))[20:24]) 29 | 30 | class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): 31 | def do_GET(self): 32 | local_ip = my_ip() 33 | remote_ip = self.client_address[0] 34 | 35 | page = INDEX_PAGE_FMT.replace('my_ip_here', local_ip).replace('your_ip_here', remote_ip) 36 | 37 | self.send_response(200) 38 | encoding = sys.getfilesystemencoding() 39 | self.send_header("Content-type", "text/html; charset=%s" % encoding) 40 | self.send_header("Content-Length", str(len(page))) 41 | self.end_headers() 42 | 43 | self.wfile.write(page) 44 | 45 | def test(HandlerClass = SimpleHTTPRequestHandler, ServerClass = BaseHTTPServer.HTTPServer): 46 | BaseHTTPServer.test(HandlerClass, ServerClass) 47 | 48 | if __name__ == '__main__': 49 | test() 50 | -------------------------------------------------------------------------------- /12-nat/include/arp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARP_H__ 2 | #define __ARP_H__ 3 | 4 | #include "base.h" 5 | #include "ether.h" 6 | #include "types.h" 7 | 8 | #define ARPHRD_ETHER 1 9 | 10 | #define ARPOP_REQUEST 1 11 | #define ARPOP_REPLY 2 12 | 13 | struct ether_arp { 14 | u16 arp_hrd; // format of hardware address, should be 0x01 15 | u16 arp_pro; // format of protocol address, should be 0x0800 16 | u8 arp_hln; // length of hardware address, should be 6 17 | u8 arp_pln; // length of protocol address, should be 4 18 | u16 arp_op; // ARP opcode (command) 19 | u8 arp_sha[ETH_ALEN]; // sender hardware address 20 | u32 arp_spa; // sender protocol address 21 | u8 arp_tha[ETH_ALEN]; // target hardware address 22 | u32 arp_tpa; // target protocol address 23 | } __attribute__ ((packed)); 24 | 25 | // get the arp header of the packet 26 | static inline struct ether_arp *packet_to_ether_arp(const char *packet) 27 | { 28 | return (struct ether_arp *)(packet + ETHER_HDR_SIZE); 29 | } 30 | 31 | void handle_arp_packet(iface_info_t *info, char *packet, int len); 32 | void arp_send_request(iface_info_t *iface, u32 dst_ip); 33 | void iface_send_packet_by_arp(iface_info_t *iface, u32 dst_ip, char *packet, int len); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /12-nat/include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE_H__ 2 | #define __BASE_H__ 3 | 4 | #include "types.h" 5 | #include "ether.h" 6 | #include "list.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | typedef struct { 28 | struct list_head iface_list; // the list of interfaces 29 | int nifs; // number of interfaces 30 | struct pollfd *fds; // structure used to poll packets among 31 | // all the interfaces 32 | } ustack_t; 33 | 34 | extern ustack_t *instance; 35 | 36 | typedef struct { 37 | struct list_head list; // list node used to link all interfaces 38 | 39 | int fd; // file descriptor for receiving & sending packets 40 | int index; // the index (unique ID) of this interface 41 | u8 mac[ETH_ALEN]; // mac address of this interface 42 | u32 ip; // IPv4 address (in host byte order) 43 | u32 mask; // Network Mask (in host byte order) 44 | char name[16]; // name of this interface 45 | char ip_str[16]; // readable IP address 46 | } iface_info_t; 47 | 48 | void init_ustack(); 49 | iface_info_t *fd_to_iface(int fd); 50 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 51 | #endif 52 | -------------------------------------------------------------------------------- /12-nat/include/checksum.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHECKSUM_H__ 2 | #define __CHECKSUM_H__ 3 | 4 | #include "types.h" 5 | 6 | // calculate the checksum of the given buf, providing sum 7 | // as the initial value 8 | static inline u16 checksum(void *t_buf, int nbytes, u32 sum) 9 | { 10 | u16 * buf = t_buf; 11 | for (int i = 0; i < nbytes / 2; i++) 12 | sum += buf[i]; 13 | 14 | if (nbytes % 2) 15 | sum += ((u8 *)buf)[nbytes-1]; 16 | 17 | while (sum >> 16) 18 | sum = (sum >> 16) + (sum & 0xffff); 19 | 20 | return (u16)~sum; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /12-nat/include/ether.h: -------------------------------------------------------------------------------- 1 | #ifndef __ETHER_H__ 2 | #define __ETHER_H__ 3 | 4 | #include "types.h" 5 | 6 | #define ETH_ALEN 6 // length of mac address 7 | #define ETH_FRAME_LEN 1514 // maximum length of an ethernet frame (packet) 8 | 9 | // protocol format in ethernet header 10 | #define ETH_P_ALL 0x0003 // every packet, only used when tending to receive all packets 11 | #define ETH_P_IP 0x0800 // IP packet 12 | #define ETH_P_ARP 0x0806 // ARP packet 13 | 14 | struct ether_header { 15 | u8 ether_dhost[ETH_ALEN]; // destination mac address 16 | u8 ether_shost[ETH_ALEN]; // source mac address 17 | u16 ether_type; // protocol format 18 | }; 19 | 20 | #define ETHER_HDR_SIZE sizeof(struct ether_header) 21 | 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /12-nat/include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __HASH_H__ 2 | #define __HASH_H__ 3 | 4 | #include "types.h" 5 | 6 | #define HASH_8BITS 256 7 | #define HASH_16BITS 65536 8 | 9 | // the simplest hash functions, you can recreate the wheels as you wish 10 | 11 | static inline u8 hash8(char *buf, int len) 12 | { 13 | u8 result = 0; 14 | for (int i = 0; i < len; i++) 15 | result ^= buf[i]; 16 | 17 | return result; 18 | } 19 | 20 | static inline u16 hash16(char *buf, int len) 21 | { 22 | u16 result = 0; 23 | for (int i = 0; i < len / 2 * 2; i += 2) 24 | result ^= *(u16 *)(buf + i); 25 | 26 | if (len % 2) 27 | result ^= (u8)(buf[len-1]); 28 | 29 | return result; 30 | } 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /12-nat/include/icmp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ICMP_H__ 2 | #define __ICMP_H__ 3 | 4 | #include "types.h" 5 | #include "checksum.h" 6 | #include "base.h" 7 | 8 | struct icmphdr { 9 | u8 type; // type of icmp message 10 | u8 code; // icmp code 11 | u16 checksum; 12 | u16 icmp_identifier; // icmp identifier, used in icmp echo request 13 | u16 icmp_sequence; // icmp sequence, used in icmp echo request 14 | }__attribute__((packed)); 15 | 16 | #define ICMP_HDR_SIZE sizeof(struct icmphdr) 17 | #define ICMP_COPIED_DATA_LEN 8 18 | 19 | #define ICMP_ECHOREQUEST 8 // echo request 20 | #define ICMP_ECHOREPLY 0 // echo reply 21 | #define ICMP_DEST_UNREACH 3 // destination unreachable 22 | #define ICMP_TIME_EXCEEDED 11 // time exceeded 23 | 24 | // codes for UNREACH 25 | #define ICMP_NET_UNREACH 0 // network unreachable 26 | #define ICMP_HOST_UNREACH 1 // host unreachable 27 | 28 | // code for TIME_EXCEEDED 29 | #define ICMP_EXC_TTL 0 // ttl count exceeded 30 | 31 | // calculate the checksum of icmp data, note that the length of icmp data varies 32 | static inline u16 icmp_checksum(struct icmphdr *icmp, int len) 33 | { 34 | u16 tmp = icmp->checksum; 35 | icmp->checksum = 0; 36 | u16 sum = checksum((u16 *)icmp, len, 0); 37 | icmp->checksum = tmp; 38 | 39 | return sum; 40 | } 41 | 42 | // construct icmp packet according to type, code and incoming packet, and send it 43 | void icmp_send_packet(const char *in_pkt, int len, u8 type, u8 code); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /12-nat/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // #define LOG_DEBUG 9 | 10 | enum log_level { DEBUG = 0, INFO, WARNING, ERROR }; 11 | 12 | static enum log_level this_log_level = DEBUG; 13 | 14 | static const char *log_level_str[] = { "DEBUG", "INFO", "WARNING", "ERROR" }; 15 | 16 | #ifdef LOG_DEBUG 17 | #define log_it(fmt, level_str, ...) \ 18 | fprintf(stderr, "[%s:%u] %s: " fmt "\n", __FILE__, __LINE__, \ 19 | level_str, ##__VA_ARGS__); 20 | #else 21 | #define log_it(fmt, level_str, ...) \ 22 | fprintf(stderr, "%s: " fmt "\n", level_str, ##__VA_ARGS__); 23 | #endif 24 | 25 | #define log(level, fmt, ...) \ 26 | do { \ 27 | if (level < this_log_level) \ 28 | break; \ 29 | log_it(fmt, log_level_str[level], ##__VA_ARGS__); \ 30 | } while (0) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /12-nat/include/rtable.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTABLE_H__ 2 | #define __RTABLE_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | #include "list.h" 8 | 9 | // structure of ip forwarding table 10 | // note: 1, the table supports only ipv4 address; 11 | // 2, addresses are stored in host byte order. 12 | typedef struct { 13 | struct list_head list; 14 | u32 dest; // destination ip address (could be network or host) 15 | u32 mask; // network mask of dest 16 | u32 gw; // ip address of next hop (will be 0 if dest is in 17 | // the same network with iface) 18 | int flags; // flags (could be omitted here) 19 | char if_name[16]; // name of the interface 20 | iface_info_t *iface; // pointer to the interface structure 21 | } rt_entry_t; 22 | 23 | extern struct list_head rtable; 24 | 25 | void init_rtable(); 26 | void load_static_rtable(); 27 | void clear_rtable(); 28 | void add_rt_entry(rt_entry_t *entry); 29 | void remove_rt_entry(rt_entry_t *entry); 30 | void print_rtable(); 31 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface); 32 | 33 | rt_entry_t *longest_prefix_match(u32 ip); 34 | u32 get_next_hop(rt_entry_t *entry, u32 dst); 35 | 36 | void load_rtable_from_kernel(); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /12-nat/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | 6 | typedef uint8_t u8; 7 | typedef uint16_t u16; 8 | typedef uint32_t u32; 9 | typedef uint64_t u64; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /12-nat/ip.c: -------------------------------------------------------------------------------- 1 | #include "ip.h" 2 | #include "icmp.h" 3 | #include "arpcache.h" 4 | #include "rtable.h" 5 | #include "arp.h" 6 | #include "nat.h" 7 | 8 | #include 9 | 10 | void handle_ip_packet(iface_info_t *iface, char *packet, int len) 11 | { 12 | struct iphdr *ip = packet_to_ip_hdr(packet); 13 | u32 daddr = ntohl(ip->daddr); 14 | if (daddr == iface->ip && ip->protocol == IPPROTO_ICMP) { 15 | struct icmphdr *icmp = (struct icmphdr *)IP_DATA(ip); 16 | if (icmp->type == ICMP_ECHOREQUEST) { 17 | icmp_send_packet(packet, len, ICMP_ECHOREPLY, 0); 18 | } 19 | 20 | free(packet); 21 | } 22 | else { 23 | nat_translate_packet(iface, packet, len); 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /12-nat/nat_complex_topo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from mininet.node import OVSBridge 4 | from mininet.topo import Topo 5 | from mininet.net import Mininet 6 | from mininet.cli import CLI 7 | 8 | class NATTopo(Topo): 9 | def build(self): 10 | h1 = self.addHost('h1') 11 | h2 = self.addHost('h2') 12 | n1 = self.addHost('n1') 13 | n2 = self.addHost('n2') 14 | 15 | self.addLink(h1, n1) 16 | self.addLink(h2, n2) 17 | self.addLink(n1, n2) 18 | 19 | if __name__ == '__main__': 20 | topo = NATTopo() 21 | net = Mininet(topo = topo, switch = OVSBridge, controller = None) 22 | 23 | h1, h2, n1, n2 = net.get('h1', 'h2', 'n1', 'n2') 24 | 25 | h1.cmd('ifconfig h1-eth0 10.0.1.11/24') 26 | h1.cmd('route add default gw 10.0.1.1') 27 | 28 | h2.cmd('ifconfig h2-eth0 10.0.2.22/24') 29 | h2.cmd('route add default gw 10.0.2.1') 30 | 31 | n1.cmd('ifconfig n1-eth0 10.0.1.1/24') 32 | n1.cmd('ifconfig n1-eth1 159.226.39.43/24') 33 | 34 | n2.cmd('ifconfig n2-eth0 10.0.2.1/24') 35 | n2.cmd('ifconfig n2-eth1 159.226.39.123/24') 36 | 37 | 38 | for h in (h1, h2): 39 | h.cmd('./scripts/disable_offloading.sh') 40 | h.cmd('./scripts/disable_ipv6.sh') 41 | 42 | for n in (n1, n2): 43 | n.cmd('./scripts/disable_arp.sh') 44 | n.cmd('./scripts/disable_icmp.sh') 45 | n.cmd('./scripts/disable_ip_forward.sh') 46 | n.cmd('./scripts/disable_ipv6.sh') 47 | 48 | for n in (n1, n2): 49 | n.cmd('stdbuf -oL ./nat exp-' + n.name + '.conf > log-' + n.name + '.txt 2> log_err-' + n.name + '.txt &') 50 | 51 | net.start() 52 | CLI(net) 53 | net.stop() 54 | -------------------------------------------------------------------------------- /12-nat/nat_topo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from mininet.node import OVSBridge 4 | from mininet.topo import Topo 5 | from mininet.net import Mininet 6 | from mininet.cli import CLI 7 | 8 | class NATTopo(Topo): 9 | def build(self): 10 | s1 = self.addSwitch('s1') 11 | h1 = self.addHost('h1') 12 | h2 = self.addHost('h2') 13 | h3 = self.addHost('h3') 14 | n1 = self.addHost('n1') 15 | 16 | self.addLink(h1, s1) 17 | self.addLink(h2, s1) 18 | self.addLink(n1, s1) 19 | self.addLink(h3, n1) 20 | 21 | if __name__ == '__main__': 22 | topo = NATTopo() 23 | net = Mininet(topo = topo, switch = OVSBridge, controller = None) 24 | 25 | h1, h2, h3, s1, n1 = net.get('h1', 'h2', 'h3', 's1', 'n1') 26 | 27 | h1.cmd('ifconfig h1-eth0 10.21.0.1/16') 28 | h1.cmd('route add default gw 10.21.0.254') 29 | 30 | h2.cmd('ifconfig h2-eth0 10.21.0.2/16') 31 | h2.cmd('route add default gw 10.21.0.254') 32 | 33 | n1.cmd('ifconfig n1-eth0 10.21.0.254/16') 34 | n1.cmd('ifconfig n1-eth1 159.226.39.43/24') 35 | 36 | h3.cmd('ifconfig h3-eth0 159.226.39.123/24') 37 | 38 | for h in (h1, h2, h3): 39 | h.cmd('./scripts/disable_offloading.sh') 40 | h.cmd('./scripts/disable_ipv6.sh') 41 | 42 | s1.cmd('./scripts/disable_ipv6.sh') 43 | 44 | n1.cmd('./scripts/disable_arp.sh') 45 | n1.cmd('./scripts/disable_icmp.sh') 46 | n1.cmd('./scripts/disable_ip_forward.sh') 47 | n1.cmd('./scripts/disable_ipv6.sh') 48 | 49 | # n1.cmd('stdbuf -oL ./nat exp1.conf > log.txt 2> log_err.txt &') 50 | n1.cmd('stdbuf -oL ./nat exp2.conf > log.txt 2> log_err.txt &') 51 | 52 | net.start() 53 | CLI(net) 54 | net.stop() 55 | -------------------------------------------------------------------------------- /12-nat/rtable.c: -------------------------------------------------------------------------------- 1 | #include "rtable.h" 2 | #include "ip.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct list_head rtable; 9 | 10 | void init_rtable() 11 | { 12 | init_list_head(&rtable); 13 | } 14 | 15 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface) 16 | { 17 | rt_entry_t *entry = malloc(sizeof(*entry)); 18 | memset(entry, 0, sizeof(*entry)); 19 | 20 | init_list_head(&(entry->list)); 21 | entry->dest = dest; 22 | entry->mask = mask; 23 | entry->gw = gw; 24 | entry->iface = iface; 25 | strcpy(entry->if_name, iface->name); 26 | 27 | return entry; 28 | } 29 | 30 | void add_rt_entry(rt_entry_t *entry) 31 | { 32 | list_add_tail(&entry->list, &rtable); 33 | } 34 | 35 | void remove_rt_entry(rt_entry_t *entry) 36 | { 37 | list_delete_entry(&entry->list); 38 | free(entry); 39 | } 40 | 41 | void clear_rtable() 42 | { 43 | struct list_head *head = &rtable, *tmp; 44 | while (head->next != head) { 45 | tmp = head->next; 46 | list_delete_entry(tmp); 47 | rt_entry_t *entry = list_entry(tmp, rt_entry_t, list); 48 | free(entry); 49 | } 50 | } 51 | 52 | void print_rtable() 53 | { 54 | // Print the route records 55 | fprintf(stdout, "Routing Table:\n"); 56 | fprintf(stdout, "dest\tmask\tgateway\tif_name\n"); 57 | fprintf(stdout, "--------------------------------------\n"); 58 | rt_entry_t *entry = NULL; 59 | list_for_each_entry(entry, &rtable, list) { 60 | fprintf(stdout, IP_FMT"\t"IP_FMT"\t"IP_FMT"\t%s\n", \ 61 | HOST_IP_FMT_STR(entry->dest), \ 62 | HOST_IP_FMT_STR(entry->mask), \ 63 | HOST_IP_FMT_STR(entry->gw), \ 64 | entry->if_name); 65 | } 66 | fprintf(stdout, "--------------------------------------\n"); 67 | } 68 | -------------------------------------------------------------------------------- /12-nat/scripts/disable_arp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | arptables -A FORWARD -j DROP 4 | arptables -A OUTPUT -j DROP 5 | -------------------------------------------------------------------------------- /12-nat/scripts/disable_icmp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p icmp --icmp-type echo-request -j DROP 4 | iptables -A OUTPUT -p icmp --icmp-type echo-reply -j DROP 5 | iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP 6 | -------------------------------------------------------------------------------- /12-nat/scripts/disable_ip_forward.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p ip -j DROP 4 | echo 0 > /proc/sys/net/ipv4/ip_forward 5 | -------------------------------------------------------------------------------- /12-nat/scripts/disable_ipv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w net.ipv6.conf.all.disable_ipv6=1 4 | sysctl -w net.ipv6.conf.default.disable_ipv6=1 5 | -------------------------------------------------------------------------------- /12-nat/scripts/disable_offloading.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The virtual NIC does not support "lro rxhash" options. 4 | TOE_OPTIONS="rx tx sg tso ufo gso gro rxvlan txvlan" 5 | 6 | for IFACE in `/sbin/ifconfig | grep '^.*-eth[0-9]' | awk '{print $1}'`; do 7 | echo "Disabling $IFACE ..." 8 | for TOE_OPTION in $TOE_OPTIONS; do 9 | /sbin/ethtool --offload "$IFACE" "$TOE_OPTION" off 10 | done 11 | done 12 | -------------------------------------------------------------------------------- /13-tcp_stack/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = tcp_stack 2 | all: $(TARGET) 3 | 4 | CC = gcc 5 | LD = gcc 6 | 7 | CFLAGS = -g -Wall -Iinclude 8 | LDFLAGS = 9 | 10 | LIBS = -lpthread 11 | 12 | HDRS = ./include/*.h 13 | 14 | SRCS = arp.c arpcache.c device_internal.c icmp.c ip_base.c ip.c main.c rtable.c rtable_internal.c \ 15 | tcp.c tcp_apps.c tcp_in.c tcp_out.c tcp_sock.c tcp_timer.c 16 | 17 | OBJS = $(patsubst %.c,%.o,$(SRCS)) 18 | 19 | $(OBJS) : %.o : %.c include/*.h 20 | $(CC) -c $(CFLAGS) $< -o $@ 21 | 22 | $(TARGET): $(OBJS) 23 | $(LD) $(LDFLAGS) $(OBJS) -o $(TARGET) $(LIBS) 24 | 25 | clean: 26 | rm -f *.o $(TARGET) 27 | -------------------------------------------------------------------------------- /13-tcp_stack/include/arp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARP_H__ 2 | #define __ARP_H__ 3 | 4 | #include "base.h" 5 | #include "ether.h" 6 | #include "types.h" 7 | 8 | #define ARPHRD_ETHER 1 9 | 10 | #define ARPOP_REQUEST 1 11 | #define ARPOP_REPLY 2 12 | 13 | struct ether_arp { 14 | u16 arp_hrd; // format of hardware address, should be 0x01 15 | u16 arp_pro; // format of protocol address, should be 0x0800 16 | u8 arp_hln; // length of hardware address, should be 6 17 | u8 arp_pln; // length of protocol address, should be 4 18 | u16 arp_op; // ARP opcode (command) 19 | u8 arp_sha[ETH_ALEN]; // sender hardware address 20 | u32 arp_spa; // sender protocol address 21 | u8 arp_tha[ETH_ALEN]; // target hardware address 22 | u32 arp_tpa; // target protocol address 23 | } __attribute__ ((packed)); 24 | 25 | // get the arp header of the packet 26 | static inline struct ether_arp *packet_to_ether_arp(const char *packet) 27 | { 28 | return (struct ether_arp *)(packet + ETHER_HDR_SIZE); 29 | } 30 | 31 | void handle_arp_packet(iface_info_t *info, char *packet, int len); 32 | void arp_send_request(iface_info_t *iface, u32 dst_ip); 33 | void iface_send_packet_by_arp(iface_info_t *iface, u32 dst_ip, char *packet, int len); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /13-tcp_stack/include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE_H__ 2 | #define __BASE_H__ 3 | 4 | #include "types.h" 5 | #include "ether.h" 6 | #include "list.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | typedef struct { 28 | struct list_head iface_list; // the list of interfaces 29 | int nifs; // number of interfaces 30 | struct pollfd *fds; // structure used to poll packets among 31 | // all the interfaces 32 | } ustack_t; 33 | 34 | extern ustack_t *instance; 35 | 36 | typedef struct { 37 | struct list_head list; // list node used to link all interfaces 38 | 39 | int fd; // file descriptor for receiving & sending packets 40 | int index; // the index (unique ID) of this interface 41 | u8 mac[ETH_ALEN]; // mac address of this interface 42 | u32 ip; // IPv4 address (in host byte order) 43 | u32 mask; // Network Mask (in host byte order) 44 | char name[16]; // name of this interface 45 | char ip_str[16]; // readable IP address 46 | } iface_info_t; 47 | 48 | void init_ustack(); 49 | iface_info_t *fd_to_iface(int fd); 50 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 51 | #endif 52 | -------------------------------------------------------------------------------- /13-tcp_stack/include/checksum.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHECKSUM_H__ 2 | #define __CHECKSUM_H__ 3 | 4 | #include "types.h" 5 | 6 | // calculate the checksum of the given buf, providing sum 7 | // as the initial value 8 | static inline u16 checksum(void *t_buf, int nbytes, u32 sum) 9 | { 10 | u16 * buf = t_buf; 11 | for (int i = 0; i < nbytes / 2; i++) 12 | sum += buf[i]; 13 | 14 | if (nbytes % 2) 15 | sum += ((u8 *)buf)[nbytes-1]; 16 | 17 | while (sum >> 16) 18 | sum = (sum >> 16) + (sum & 0xffff); 19 | 20 | return (u16)~sum; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /13-tcp_stack/include/ether.h: -------------------------------------------------------------------------------- 1 | #ifndef __ETHER_H__ 2 | #define __ETHER_H__ 3 | 4 | #include "types.h" 5 | 6 | #define ETH_ALEN 6 // length of mac address 7 | #define ETH_FRAME_LEN 1514 // maximum length of an ethernet frame (packet) 8 | 9 | // protocol format in ethernet header 10 | #define ETH_P_ALL 0x0003 // every packet, only used when tending to receive all packets 11 | #define ETH_P_IP 0x0800 // IP packet 12 | #define ETH_P_ARP 0x0806 // ARP packet 13 | 14 | struct ether_header { 15 | u8 ether_dhost[ETH_ALEN]; // destination mac address 16 | u8 ether_shost[ETH_ALEN]; // source mac address 17 | u16 ether_type; // protocol format 18 | }; 19 | 20 | #define ETHER_HDR_SIZE sizeof(struct ether_header) 21 | 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /13-tcp_stack/include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __HASH_H__ 2 | #define __HASH_H__ 3 | 4 | #include "types.h" 5 | 6 | #define HASH_8BITS 256 7 | #define HASH_16BITS 65536 8 | 9 | // the simplest hash functions, you can recreate the wheels as you wish 10 | 11 | static inline u8 hash8(char *buf, int len) 12 | { 13 | u8 result = 0; 14 | for (int i = 0; i < len; i++) 15 | result ^= buf[i]; 16 | 17 | return result; 18 | } 19 | 20 | static inline u16 hash16(char *buf, int len) 21 | { 22 | u16 result = 0; 23 | for (int i = 0; i < len / 2 * 2; i += 2) 24 | result ^= *(u16 *)(buf + i); 25 | 26 | if (len % 2) 27 | result ^= (u8)(buf[len-1]); 28 | 29 | return result; 30 | } 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /13-tcp_stack/include/icmp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ICMP_H__ 2 | #define __ICMP_H__ 3 | 4 | #include "types.h" 5 | #include "checksum.h" 6 | #include "base.h" 7 | 8 | struct icmphdr { 9 | u8 type; // type of icmp message 10 | u8 code; // icmp code 11 | u16 checksum; 12 | u16 icmp_identifier; // icmp identifier, used in icmp echo request 13 | u16 icmp_sequence; // icmp sequence, used in icmp echo request 14 | }__attribute__((packed)); 15 | 16 | #define ICMP_HDR_SIZE sizeof(struct icmphdr) 17 | #define ICMP_COPIED_DATA_LEN 8 18 | 19 | #define ICMP_ECHOREQUEST 8 // echo request 20 | #define ICMP_ECHOREPLY 0 // echo reply 21 | #define ICMP_DEST_UNREACH 3 // destination unreachable 22 | #define ICMP_TIME_EXCEEDED 11 // time exceeded 23 | 24 | // codes for UNREACH 25 | #define ICMP_NET_UNREACH 0 // network unreachable 26 | #define ICMP_HOST_UNREACH 1 // host unreachable 27 | 28 | // code for TIME_EXCEEDED 29 | #define ICMP_EXC_TTL 0 // ttl count exceeded 30 | 31 | // calculate the checksum of icmp data, note that the length of icmp data varies 32 | static inline u16 icmp_checksum(struct icmphdr *icmp, int len) 33 | { 34 | u16 tmp = icmp->checksum; 35 | icmp->checksum = 0; 36 | u16 sum = checksum((u16 *)icmp, len, 0); 37 | icmp->checksum = tmp; 38 | 39 | return sum; 40 | } 41 | 42 | // construct icmp packet according to type, code and incoming packet, and send it 43 | void icmp_send_packet(const char *in_pkt, int len, u8 type, u8 code); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /13-tcp_stack/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // #define LOG_DEBUG 9 | 10 | enum log_level { DEBUG = 0, INFO, WARNING, ERROR }; 11 | 12 | static enum log_level this_log_level = DEBUG; 13 | 14 | static const char *log_level_str[] = { "DEBUG", "INFO", "WARNING", "ERROR" }; 15 | 16 | #ifdef LOG_DEBUG 17 | #define log_it(fmt, level_str, ...) \ 18 | fprintf(stderr, "[%s:%u] %s: " fmt "\n", __FILE__, __LINE__, \ 19 | level_str, ##__VA_ARGS__); 20 | #else 21 | #define log_it(fmt, level_str, ...) \ 22 | fprintf(stderr, "%s: " fmt "\n", level_str, ##__VA_ARGS__); 23 | #endif 24 | 25 | #define log(level, fmt, ...) \ 26 | do { \ 27 | if (level < this_log_level) \ 28 | break; \ 29 | log_it(fmt, log_level_str[level], ##__VA_ARGS__); \ 30 | } while (0) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /13-tcp_stack/include/packet.h: -------------------------------------------------------------------------------- 1 | #ifndef __PACKET_H__ 2 | #define __PACKET_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 8 | void broadcast_packet(iface_info_t *iface, char *packet, int len); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /13-tcp_stack/include/rtable.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTABLE_H__ 2 | #define __RTABLE_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | #include "list.h" 8 | 9 | // structure of ip forwarding table 10 | // note: 1, the table supports only ipv4 address; 11 | // 2, addresses are stored in host byte order. 12 | typedef struct { 13 | struct list_head list; 14 | u32 dest; // destination ip address (could be network or host) 15 | u32 mask; // network mask of dest 16 | u32 gw; // ip address of next hop (will be 0 if dest is in 17 | // the same network with iface) 18 | int flags; // flags (could be omitted here) 19 | char if_name[16]; // name of the interface 20 | iface_info_t *iface; // pointer to the interface structure 21 | } rt_entry_t; 22 | 23 | extern struct list_head rtable; 24 | 25 | void init_rtable(); 26 | void load_static_rtable(); 27 | void clear_rtable(); 28 | void add_rt_entry(rt_entry_t *entry); 29 | void remove_rt_entry(rt_entry_t *entry); 30 | void print_rtable(); 31 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface); 32 | 33 | rt_entry_t *longest_prefix_match(u32 ip); 34 | u32 get_next_hop(rt_entry_t *entry, u32 dst); 35 | 36 | void load_rtable_from_kernel(); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /13-tcp_stack/include/tcp_apps.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_APPS_H__ 2 | #define __TCP_APPS_H__ 3 | 4 | 5 | void *tcp_server(void *arg); 6 | void *tcp_client(void *arg); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /13-tcp_stack/include/tcp_hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_HASH_H__ 2 | #define __TCP_HASH_H__ 3 | 4 | #include "hash.h" 5 | #include "list.h" 6 | #include "tcp_sock.h" 7 | 8 | #define TCP_HASH_SIZE HASH_8BITS 9 | #define TCP_HASH_MASK (TCP_HASH_SIZE - 1) 10 | 11 | // the 3 tables in tcp_hash_table 12 | struct tcp_hash_table { 13 | struct list_head established_table[TCP_HASH_SIZE]; 14 | struct list_head listen_table[TCP_HASH_SIZE]; 15 | struct list_head bind_table[TCP_HASH_SIZE]; 16 | }; 17 | 18 | // tcp hash function: if hashed into bind_table or listen_table, only use sport; 19 | // otherwise, use all the 4 arguments 20 | static inline int tcp_hash_function(u32 saddr, u32 daddr, u16 sport, u16 dport) 21 | { 22 | int result = hash8((char *)&saddr, 4) ^ hash8((char *)&daddr, 4) ^ \ 23 | hash8((char *)&sport, 2) ^ hash8((char *)&dport, 2); 24 | 25 | return result & TCP_HASH_MASK; 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /13-tcp_stack/include/tcp_timer.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_TIMER_H__ 2 | #define __TCP_TIMER_H__ 3 | 4 | #include "list.h" 5 | 6 | #include 7 | 8 | struct tcp_timer { 9 | int type; // time-wait: 0 retrans: 1 10 | #define TIMER_TYPE_TIME_WAIT 0 11 | #define TIMER_TYPE_RETRANS 1 12 | 13 | int timeout; // in micro second 14 | struct list_head list; 15 | int enable; 16 | }; 17 | 18 | struct tcp_sock; 19 | #define timewait_to_tcp_sock(t) \ 20 | (struct tcp_sock *)((char *)(t) - offsetof(struct tcp_sock, timewait)) 21 | 22 | #define retranstimer_to_tcp_sock(t) \ 23 | (struct tcp_sock *)((char *)(t) - offsetof(struct tcp_sock, retrans_timer)) 24 | #define TCP_TIMER_SCAN_INTERVAL 100000 25 | #define TCP_MSL 1000000 26 | #define TCP_TIMEWAIT_TIMEOUT (2 * TCP_MSL) 27 | #define TCP_RETRANS_INTERVAL_INITIAL 200000 28 | 29 | // the thread that scans timer_list periodically 30 | void *tcp_timer_thread(void *arg); 31 | // add the timer of tcp sock to timer_list 32 | void tcp_set_timewait_timer(struct tcp_sock *); 33 | 34 | void tcp_set_retrans_timer(struct tcp_sock *tsk); 35 | 36 | void tcp_unset_retrans_timer(struct tcp_sock *tsk); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /13-tcp_stack/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | 6 | typedef uint8_t u8; 7 | typedef uint16_t u16; 8 | typedef uint32_t u32; 9 | typedef uint64_t u64; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /13-tcp_stack/ip.c: -------------------------------------------------------------------------------- 1 | #include "ip.h" 2 | #include "icmp.h" 3 | #include "arpcache.h" 4 | #include "rtable.h" 5 | #include "arp.h" 6 | #include "tcp.h" 7 | 8 | #include "log.h" 9 | 10 | #include 11 | 12 | 13 | void handle_ip_packet(iface_info_t *iface, char *packet, int len) 14 | { 15 | struct iphdr *ip = packet_to_ip_hdr(packet); 16 | u32 daddr = ntohl(ip->daddr); 17 | if (daddr == iface->ip) { 18 | if (ip->protocol == IPPROTO_ICMP) { 19 | struct icmphdr *icmp = (struct icmphdr *)IP_DATA(ip); 20 | if (icmp->type == ICMP_ECHOREQUEST) { 21 | icmp_send_packet(packet, len, ICMP_ECHOREPLY, 0); 22 | } 23 | } 24 | else if (ip->protocol == IPPROTO_TCP) { 25 | handle_tcp_packet(packet, ip, (struct tcphdr *)(IP_DATA(ip))); 26 | } 27 | else { 28 | log(ERROR, "unsupported IP protocol (0x%x) packet.", ip->protocol); 29 | } 30 | 31 | free(packet); 32 | } 33 | else { 34 | // ip_forward_packet(daddr, packet, len); 35 | log(ERROR, "received packet with incorrect destination IP address."); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /13-tcp_stack/rtable.c: -------------------------------------------------------------------------------- 1 | #include "rtable.h" 2 | #include "ip.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct list_head rtable; 9 | 10 | void init_rtable() 11 | { 12 | init_list_head(&rtable); 13 | } 14 | 15 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface) 16 | { 17 | rt_entry_t *entry = malloc(sizeof(*entry)); 18 | memset(entry, 0, sizeof(*entry)); 19 | 20 | init_list_head(&(entry->list)); 21 | entry->dest = dest; 22 | entry->mask = mask; 23 | entry->gw = gw; 24 | entry->iface = iface; 25 | strcpy(entry->if_name, iface->name); 26 | 27 | return entry; 28 | } 29 | 30 | void add_rt_entry(rt_entry_t *entry) 31 | { 32 | list_add_tail(&entry->list, &rtable); 33 | } 34 | 35 | void remove_rt_entry(rt_entry_t *entry) 36 | { 37 | list_delete_entry(&entry->list); 38 | free(entry); 39 | } 40 | 41 | void clear_rtable() 42 | { 43 | struct list_head *head = &rtable, *tmp; 44 | while (head->next != head) { 45 | tmp = head->next; 46 | list_delete_entry(tmp); 47 | rt_entry_t *entry = list_entry(tmp, rt_entry_t, list); 48 | free(entry); 49 | } 50 | } 51 | 52 | void print_rtable() 53 | { 54 | // Print the routing table 55 | fprintf(stdout, "Routing Table:\n"); 56 | fprintf(stdout, "dest\tmask\tgateway\tif_name\n"); 57 | fprintf(stdout, "--------------------------------------\n"); 58 | rt_entry_t *entry = NULL; 59 | list_for_each_entry(entry, &rtable, list) { 60 | fprintf(stdout, IP_FMT"\t"IP_FMT"\t"IP_FMT"\t%s\n", \ 61 | HOST_IP_FMT_STR(entry->dest), \ 62 | HOST_IP_FMT_STR(entry->mask), \ 63 | HOST_IP_FMT_STR(entry->gw), \ 64 | entry->if_name); 65 | } 66 | fprintf(stdout, "--------------------------------------\n"); 67 | } 68 | -------------------------------------------------------------------------------- /13-tcp_stack/scripts/disable_arp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | arptables -A FORWARD -j DROP 4 | arptables -A OUTPUT -j DROP 5 | -------------------------------------------------------------------------------- /13-tcp_stack/scripts/disable_icmp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p icmp --icmp-type echo-request -j DROP 4 | iptables -A OUTPUT -p icmp --icmp-type echo-reply -j DROP 5 | iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP 6 | -------------------------------------------------------------------------------- /13-tcp_stack/scripts/disable_ip_forward.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p ip -j DROP 4 | echo 0 > /proc/sys/net/ipv4/ip_forward 5 | -------------------------------------------------------------------------------- /13-tcp_stack/scripts/disable_ipv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w net.ipv6.conf.all.disable_ipv6=1 4 | sysctl -w net.ipv6.conf.default.disable_ipv6=1 5 | -------------------------------------------------------------------------------- /13-tcp_stack/scripts/disable_offloading.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The virtual NIC does not support "lro rxhash" options. 4 | TOE_OPTIONS="rx tx sg tso ufo gso gro rxvlan txvlan" 5 | 6 | for IFACE in `/sbin/ifconfig | grep '^.*-eth[0-9]' | awk '{print $1}'`; do 7 | echo "Disabling $IFACE ..." 8 | for TOE_OPTION in $TOE_OPTIONS; do 9 | /sbin/ethtool --offload "$IFACE" "$TOE_OPTION" off 10 | done 11 | done 12 | -------------------------------------------------------------------------------- /13-tcp_stack/scripts/disable_tcp_rst.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP 4 | -------------------------------------------------------------------------------- /13-tcp_stack/tcp_apps.c: -------------------------------------------------------------------------------- 1 | #include "tcp_sock.h" 2 | 3 | #include "log.h" 4 | 5 | #include 6 | 7 | // tcp server application, listens to port (specified by arg) and serves only one 8 | // connection request 9 | void *tcp_server(void *arg) 10 | { 11 | u16 port = *(u16 *)arg; 12 | struct tcp_sock *tsk = alloc_tcp_sock(); 13 | 14 | struct sock_addr addr; 15 | addr.ip = htonl(0); 16 | addr.port = port; 17 | if (tcp_sock_bind(tsk, &addr) < 0) { 18 | log(ERROR, "tcp_sock bind to port %hu failed", ntohs(port)); 19 | exit(1); 20 | } 21 | 22 | if (tcp_sock_listen(tsk, 3) < 0) { 23 | log(ERROR, "tcp_sock listen failed"); 24 | exit(1); 25 | } 26 | 27 | log(DEBUG, "listen to port %hu.", ntohs(port)); 28 | 29 | struct tcp_sock *csk = tcp_sock_accept(tsk); 30 | 31 | log(DEBUG, "accept a connection."); 32 | 33 | sleep(5); 34 | 35 | tcp_sock_close(csk); 36 | 37 | tcp_sock_close(tsk); 38 | 39 | return NULL; 40 | } 41 | 42 | // tcp client application, connects to server (ip:port specified by arg), each 43 | // time sends one bulk of data and receives one bulk of data 44 | void *tcp_client(void *arg) 45 | { 46 | struct sock_addr *skaddr = arg; 47 | 48 | struct tcp_sock *tsk = alloc_tcp_sock(); 49 | 50 | if (tcp_sock_connect(tsk, skaddr) < 0) { 51 | log(ERROR, "tcp_sock connect to server ("IP_FMT":%hu)failed.", \ 52 | NET_IP_FMT_STR(skaddr->ip), ntohs(skaddr->port)); 53 | exit(1); 54 | } 55 | 56 | sleep(1); 57 | 58 | tcp_sock_close(tsk); 59 | 60 | return NULL; 61 | } 62 | -------------------------------------------------------------------------------- /13-tcp_stack/tcp_stack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import string 5 | import socket 6 | from time import sleep 7 | 8 | 9 | def server(port): 10 | s = socket.socket() 11 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 12 | 13 | s.bind(('0.0.0.0', int(port))) 14 | s.listen(3) 15 | 16 | cs, addr = s.accept() 17 | 18 | sleep(5) 19 | 20 | s.close() 21 | 22 | 23 | def client(ip, port): 24 | s = socket.socket() 25 | s.connect((ip, int(port))) 26 | 27 | sleep(1) 28 | 29 | s.close() 30 | print("closed") 31 | 32 | if __name__ == '__main__': 33 | if sys.argv[1] == 'server': 34 | server(sys.argv[2]) 35 | elif sys.argv[1] == 'client': 36 | client(sys.argv[2], sys.argv[3]) 37 | -------------------------------------------------------------------------------- /15-tcp_stack/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = tcp_stack 2 | all: $(TARGET) 3 | 4 | CC = gcc 5 | LD = gcc 6 | 7 | CFLAGS = -g -Wall -Iinclude 8 | LDFLAGS = 9 | 10 | LIBS = -lpthread 11 | 12 | HDRS = ./include/*.h 13 | 14 | SRCS = arp.c arpcache.c device_internal.c icmp.c ip_base.c ip.c main.c rtable.c rtable_internal.c \ 15 | tcp.c tcp_apps.c tcp_in.c tcp_out.c tcp_sock.c tcp_timer.c 16 | 17 | OBJS = $(patsubst %.c,%.o,$(SRCS)) 18 | 19 | $(OBJS) : %.o : %.c include/*.h 20 | $(CC) -c $(CFLAGS) $< -o $@ 21 | 22 | $(TARGET): $(OBJS) 23 | $(LD) $(LDFLAGS) $(OBJS) -o $(TARGET) $(LIBS) 24 | 25 | clean: 26 | rm -f *.o $(TARGET) 27 | -------------------------------------------------------------------------------- /15-tcp_stack/create_randfile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dd if=/dev/urandom bs=1MB count=3 | base64 > client-input.dat 4 | -------------------------------------------------------------------------------- /15-tcp_stack/include/arp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARP_H__ 2 | #define __ARP_H__ 3 | 4 | #include "base.h" 5 | #include "ether.h" 6 | #include "types.h" 7 | 8 | #define ARPHRD_ETHER 1 9 | 10 | #define ARPOP_REQUEST 1 11 | #define ARPOP_REPLY 2 12 | 13 | struct ether_arp { 14 | u16 arp_hrd; // format of hardware address, should be 0x01 15 | u16 arp_pro; // format of protocol address, should be 0x0800 16 | u8 arp_hln; // length of hardware address, should be 6 17 | u8 arp_pln; // length of protocol address, should be 4 18 | u16 arp_op; // ARP opcode (command) 19 | u8 arp_sha[ETH_ALEN]; // sender hardware address 20 | u32 arp_spa; // sender protocol address 21 | u8 arp_tha[ETH_ALEN]; // target hardware address 22 | u32 arp_tpa; // target protocol address 23 | } __attribute__ ((packed)); 24 | 25 | // get the arp header of the packet 26 | static inline struct ether_arp *packet_to_ether_arp(const char *packet) 27 | { 28 | return (struct ether_arp *)(packet + ETHER_HDR_SIZE); 29 | } 30 | 31 | void handle_arp_packet(iface_info_t *info, char *packet, int len); 32 | void arp_send_request(iface_info_t *iface, u32 dst_ip); 33 | void iface_send_packet_by_arp(iface_info_t *iface, u32 dst_ip, char *packet, int len); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /15-tcp_stack/include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE_H__ 2 | #define __BASE_H__ 3 | 4 | #include "types.h" 5 | #include "ether.h" 6 | #include "list.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | typedef struct { 28 | struct list_head iface_list; // the list of interfaces 29 | int nifs; // number of interfaces 30 | struct pollfd *fds; // structure used to poll packets among 31 | // all the interfaces 32 | } ustack_t; 33 | 34 | extern ustack_t *instance; 35 | 36 | typedef struct { 37 | struct list_head list; // list node used to link all interfaces 38 | 39 | int fd; // file descriptor for receiving & sending packets 40 | int index; // the index (unique ID) of this interface 41 | u8 mac[ETH_ALEN]; // mac address of this interface 42 | u32 ip; // IPv4 address (in host byte order) 43 | u32 mask; // Network Mask (in host byte order) 44 | char name[16]; // name of this interface 45 | char ip_str[16]; // readable IP address 46 | } iface_info_t; 47 | 48 | void init_ustack(); 49 | iface_info_t *fd_to_iface(int fd); 50 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 51 | #endif 52 | -------------------------------------------------------------------------------- /15-tcp_stack/include/checksum.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHECKSUM_H__ 2 | #define __CHECKSUM_H__ 3 | 4 | #include "types.h" 5 | 6 | // calculate the checksum of the given buf, providing sum 7 | // as the initial value 8 | static inline u16 checksum(void *t_buf, int nbytes, u32 sum) 9 | { 10 | u16 * buf = t_buf; 11 | for (int i = 0; i < nbytes / 2; i++) 12 | sum += buf[i]; 13 | 14 | if (nbytes % 2) 15 | sum += ((u8 *)buf)[nbytes-1]; 16 | 17 | while (sum >> 16) 18 | sum = (sum >> 16) + (sum & 0xffff); 19 | 20 | return (u16)~sum; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /15-tcp_stack/include/ether.h: -------------------------------------------------------------------------------- 1 | #ifndef __ETHER_H__ 2 | #define __ETHER_H__ 3 | 4 | #include "types.h" 5 | 6 | #define ETH_ALEN 6 // length of mac address 7 | #define ETH_FRAME_LEN 1514 // maximum length of an ethernet frame (packet) 8 | 9 | // protocol format in ethernet header 10 | #define ETH_P_ALL 0x0003 // every packet, only used when tending to receive all packets 11 | #define ETH_P_IP 0x0800 // IP packet 12 | #define ETH_P_ARP 0x0806 // ARP packet 13 | 14 | struct ether_header { 15 | u8 ether_dhost[ETH_ALEN]; // destination mac address 16 | u8 ether_shost[ETH_ALEN]; // source mac address 17 | u16 ether_type; // protocol format 18 | }; 19 | 20 | #define ETHER_HDR_SIZE sizeof(struct ether_header) 21 | 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /15-tcp_stack/include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __HASH_H__ 2 | #define __HASH_H__ 3 | 4 | #include "types.h" 5 | 6 | #define HASH_8BITS 256 7 | #define HASH_16BITS 65536 8 | 9 | // the simplest hash functions, you can recreate the wheels as you wish 10 | 11 | static inline u8 hash8(char *buf, int len) 12 | { 13 | u8 result = 0; 14 | for (int i = 0; i < len; i++) 15 | result ^= buf[i]; 16 | 17 | return result; 18 | } 19 | 20 | static inline u16 hash16(char *buf, int len) 21 | { 22 | u16 result = 0; 23 | for (int i = 0; i < len / 2 * 2; i += 2) 24 | result ^= *(u16 *)(buf + i); 25 | 26 | if (len % 2) 27 | result ^= (u8)(buf[len-1]); 28 | 29 | return result; 30 | } 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /15-tcp_stack/include/icmp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ICMP_H__ 2 | #define __ICMP_H__ 3 | 4 | #include "types.h" 5 | #include "checksum.h" 6 | #include "base.h" 7 | 8 | struct icmphdr { 9 | u8 type; // type of icmp message 10 | u8 code; // icmp code 11 | u16 checksum; 12 | u16 icmp_identifier; // icmp identifier, used in icmp echo request 13 | u16 icmp_sequence; // icmp sequence, used in icmp echo request 14 | }__attribute__((packed)); 15 | 16 | #define ICMP_HDR_SIZE sizeof(struct icmphdr) 17 | #define ICMP_COPIED_DATA_LEN 8 18 | 19 | #define ICMP_ECHOREQUEST 8 // echo request 20 | #define ICMP_ECHOREPLY 0 // echo reply 21 | #define ICMP_DEST_UNREACH 3 // destination unreachable 22 | #define ICMP_TIME_EXCEEDED 11 // time exceeded 23 | 24 | // codes for UNREACH 25 | #define ICMP_NET_UNREACH 0 // network unreachable 26 | #define ICMP_HOST_UNREACH 1 // host unreachable 27 | 28 | // code for TIME_EXCEEDED 29 | #define ICMP_EXC_TTL 0 // ttl count exceeded 30 | 31 | // calculate the checksum of icmp data, note that the length of icmp data varies 32 | static inline u16 icmp_checksum(struct icmphdr *icmp, int len) 33 | { 34 | u16 tmp = icmp->checksum; 35 | icmp->checksum = 0; 36 | u16 sum = checksum((u16 *)icmp, len, 0); 37 | icmp->checksum = tmp; 38 | 39 | return sum; 40 | } 41 | 42 | // construct icmp packet according to type, code and incoming packet, and send it 43 | void icmp_send_packet(const char *in_pkt, int len, u8 type, u8 code); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /15-tcp_stack/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // #define LOG_DEBUG 9 | 10 | enum log_level { DEBUG = 0, INFO, WARNING, ERROR }; 11 | 12 | static enum log_level this_log_level = DEBUG; 13 | 14 | static const char *log_level_str[] = { "DEBUG", "INFO", "WARNING", "ERROR" }; 15 | 16 | #ifdef LOG_DEBUG 17 | #define log_it(fmt, level_str, ...) \ 18 | fprintf(stderr, "[%s:%u] %s: " fmt "\n", __FILE__, __LINE__, \ 19 | level_str, ##__VA_ARGS__); 20 | #else 21 | #define log_it(fmt, level_str, ...) \ 22 | fprintf(stderr, "%s: " fmt "\n", level_str, ##__VA_ARGS__); 23 | #endif 24 | 25 | #define log(level, fmt, ...) \ 26 | do { \ 27 | if (level < this_log_level) \ 28 | break; \ 29 | log_it(fmt, log_level_str[level], ##__VA_ARGS__); \ 30 | } while (0) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /15-tcp_stack/include/packet.h: -------------------------------------------------------------------------------- 1 | #ifndef __PACKET_H__ 2 | #define __PACKET_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 8 | void broadcast_packet(iface_info_t *iface, char *packet, int len); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /15-tcp_stack/include/rtable.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTABLE_H__ 2 | #define __RTABLE_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | #include "list.h" 8 | 9 | // structure of ip forwarding table 10 | // note: 1, the table supports only ipv4 address; 11 | // 2, addresses are stored in host byte order. 12 | typedef struct { 13 | struct list_head list; 14 | u32 dest; // destination ip address (could be network or host) 15 | u32 mask; // network mask of dest 16 | u32 gw; // ip address of next hop (will be 0 if dest is in 17 | // the same network with iface) 18 | int flags; // flags (could be omitted here) 19 | char if_name[16]; // name of the interface 20 | iface_info_t *iface; // pointer to the interface structure 21 | } rt_entry_t; 22 | 23 | extern struct list_head rtable; 24 | 25 | void init_rtable(); 26 | void load_static_rtable(); 27 | void clear_rtable(); 28 | void add_rt_entry(rt_entry_t *entry); 29 | void remove_rt_entry(rt_entry_t *entry); 30 | void print_rtable(); 31 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface); 32 | 33 | rt_entry_t *longest_prefix_match(u32 ip); 34 | u32 get_next_hop(rt_entry_t *entry, u32 dst); 35 | 36 | void load_rtable_from_kernel(); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /15-tcp_stack/include/tcp_apps.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_APPS_H__ 2 | #define __TCP_APPS_H__ 3 | 4 | extern char filename[100]; 5 | 6 | void *tcp_server(void *arg); 7 | void *tcp_client(void *arg); 8 | 9 | void *tcp_server_file(void *arg); 10 | void *tcp_client_file(void *arg); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /15-tcp_stack/include/tcp_hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_HASH_H__ 2 | #define __TCP_HASH_H__ 3 | 4 | #include "hash.h" 5 | #include "list.h" 6 | #include "tcp_sock.h" 7 | 8 | #define TCP_HASH_SIZE HASH_8BITS 9 | #define TCP_HASH_MASK (TCP_HASH_SIZE - 1) 10 | 11 | // the 3 tables in tcp_hash_table 12 | struct tcp_hash_table { 13 | struct list_head established_table[TCP_HASH_SIZE]; 14 | struct list_head listen_table[TCP_HASH_SIZE]; 15 | struct list_head bind_table[TCP_HASH_SIZE]; 16 | }; 17 | 18 | // tcp hash function: if hashed into bind_table or listen_table, only use sport; 19 | // otherwise, use all the 4 arguments 20 | static inline int tcp_hash_function(u32 saddr, u32 daddr, u16 sport, u16 dport) 21 | { 22 | int result = hash8((char *)&saddr, 4) ^ hash8((char *)&daddr, 4) ^ \ 23 | hash8((char *)&sport, 2) ^ hash8((char *)&dport, 2); 24 | 25 | return result & TCP_HASH_MASK; 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /15-tcp_stack/include/tcp_timer.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_TIMER_H__ 2 | #define __TCP_TIMER_H__ 3 | 4 | #include "list.h" 5 | 6 | #include 7 | 8 | struct tcp_timer { 9 | int type; // time-wait: 0 retrans: 1 10 | #define TIMER_TYPE_TIME_WAIT 0 11 | #define TIMER_TYPE_RETRANS 1 12 | 13 | int timeout; // in micro second 14 | struct list_head list; 15 | int enable; 16 | }; 17 | 18 | struct tcp_sock; 19 | #define timewait_to_tcp_sock(t) \ 20 | (struct tcp_sock *)((char *)(t) - offsetof(struct tcp_sock, timewait)) 21 | 22 | #define retranstimer_to_tcp_sock(t) \ 23 | (struct tcp_sock *)((char *)(t) - offsetof(struct tcp_sock, retrans_timer)) 24 | #define TCP_TIMER_SCAN_INTERVAL 100000 25 | #define TCP_MSL 1000000 26 | #define TCP_TIMEWAIT_TIMEOUT (2 * TCP_MSL) 27 | #define TCP_RETRANS_INTERVAL_INITIAL 200000 28 | 29 | // the thread that scans timer_list periodically 30 | void *tcp_timer_thread(void *arg); 31 | // add the timer of tcp sock to timer_list 32 | void tcp_set_timewait_timer(struct tcp_sock *); 33 | 34 | void tcp_set_retrans_timer(struct tcp_sock *tsk); 35 | 36 | void tcp_unset_retrans_timer(struct tcp_sock *tsk); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /15-tcp_stack/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | 6 | typedef uint8_t u8; 7 | typedef uint16_t u16; 8 | typedef uint32_t u32; 9 | typedef uint64_t u64; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /15-tcp_stack/ip.c: -------------------------------------------------------------------------------- 1 | #include "ip.h" 2 | #include "icmp.h" 3 | #include "arpcache.h" 4 | #include "rtable.h" 5 | #include "arp.h" 6 | #include "tcp.h" 7 | 8 | #include "log.h" 9 | 10 | #include 11 | 12 | 13 | void handle_ip_packet(iface_info_t *iface, char *packet, int len) 14 | { 15 | struct iphdr *ip = packet_to_ip_hdr(packet); 16 | u32 daddr = ntohl(ip->daddr); 17 | if (daddr == iface->ip) { 18 | if (ip->protocol == IPPROTO_ICMP) { 19 | struct icmphdr *icmp = (struct icmphdr *)IP_DATA(ip); 20 | if (icmp->type == ICMP_ECHOREQUEST) { 21 | icmp_send_packet(packet, len, ICMP_ECHOREPLY, 0); 22 | } 23 | } 24 | else if (ip->protocol == IPPROTO_TCP) { 25 | handle_tcp_packet(packet, ip, (struct tcphdr *)(IP_DATA(ip))); 26 | } 27 | else { 28 | log(ERROR, "unsupported IP protocol (0x%x) packet.", ip->protocol); 29 | } 30 | 31 | free(packet); 32 | } 33 | else { 34 | // ip_forward_packet(daddr, packet, len); 35 | log(ERROR, "received packet with incorrect destination IP address."); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /15-tcp_stack/rtable.c: -------------------------------------------------------------------------------- 1 | #include "rtable.h" 2 | #include "ip.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct list_head rtable; 9 | 10 | void init_rtable() 11 | { 12 | init_list_head(&rtable); 13 | } 14 | 15 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface) 16 | { 17 | rt_entry_t *entry = malloc(sizeof(*entry)); 18 | memset(entry, 0, sizeof(*entry)); 19 | 20 | init_list_head(&(entry->list)); 21 | entry->dest = dest; 22 | entry->mask = mask; 23 | entry->gw = gw; 24 | entry->iface = iface; 25 | strcpy(entry->if_name, iface->name); 26 | 27 | return entry; 28 | } 29 | 30 | void add_rt_entry(rt_entry_t *entry) 31 | { 32 | list_add_tail(&entry->list, &rtable); 33 | } 34 | 35 | void remove_rt_entry(rt_entry_t *entry) 36 | { 37 | list_delete_entry(&entry->list); 38 | free(entry); 39 | } 40 | 41 | void clear_rtable() 42 | { 43 | struct list_head *head = &rtable, *tmp; 44 | while (head->next != head) { 45 | tmp = head->next; 46 | list_delete_entry(tmp); 47 | rt_entry_t *entry = list_entry(tmp, rt_entry_t, list); 48 | free(entry); 49 | } 50 | } 51 | 52 | void print_rtable() 53 | { 54 | // Print the routing table 55 | fprintf(stdout, "Routing Table:\n"); 56 | fprintf(stdout, "dest\tmask\tgateway\tif_name\n"); 57 | fprintf(stdout, "--------------------------------------\n"); 58 | rt_entry_t *entry = NULL; 59 | list_for_each_entry(entry, &rtable, list) { 60 | fprintf(stdout, IP_FMT"\t"IP_FMT"\t"IP_FMT"\t%s\n", \ 61 | HOST_IP_FMT_STR(entry->dest), \ 62 | HOST_IP_FMT_STR(entry->mask), \ 63 | HOST_IP_FMT_STR(entry->gw), \ 64 | entry->if_name); 65 | } 66 | fprintf(stdout, "--------------------------------------\n"); 67 | } 68 | -------------------------------------------------------------------------------- /15-tcp_stack/scripts/disable_arp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | arptables -A FORWARD -j DROP 4 | arptables -A OUTPUT -j DROP 5 | -------------------------------------------------------------------------------- /15-tcp_stack/scripts/disable_icmp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p icmp --icmp-type echo-request -j DROP 4 | iptables -A OUTPUT -p icmp --icmp-type echo-reply -j DROP 5 | iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP 6 | -------------------------------------------------------------------------------- /15-tcp_stack/scripts/disable_ip_forward.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p ip -j DROP 4 | echo 0 > /proc/sys/net/ipv4/ip_forward 5 | -------------------------------------------------------------------------------- /15-tcp_stack/scripts/disable_ipv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w net.ipv6.conf.all.disable_ipv6=1 4 | sysctl -w net.ipv6.conf.default.disable_ipv6=1 5 | -------------------------------------------------------------------------------- /15-tcp_stack/scripts/disable_offloading.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The virtual NIC does not support "lro rxhash" options. 4 | TOE_OPTIONS="rx tx sg tso ufo gso gro rxvlan txvlan" 5 | 6 | for IFACE in `/sbin/ifconfig | grep '^.*-eth[0-9]' | awk '{print $1}'`; do 7 | echo "Disabling $IFACE ..." 8 | for TOE_OPTION in $TOE_OPTIONS; do 9 | /sbin/ethtool --offload "$IFACE" "$TOE_OPTION" off 10 | done 11 | done 12 | -------------------------------------------------------------------------------- /15-tcp_stack/scripts/disable_tcp_rst.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP 4 | -------------------------------------------------------------------------------- /15-tcp_stack/tcp_stack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import sys 4 | import string 5 | import socket 6 | from time import sleep 7 | 8 | data = string.digits + string.lowercase + string.uppercase 9 | 10 | def server(port): 11 | s = socket.socket() 12 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 13 | 14 | s.bind(('0.0.0.0', int(port))) 15 | s.listen(3) 16 | 17 | cs, addr = s.accept() 18 | print addr 19 | 20 | while True: 21 | data = cs.recv(1000) 22 | print(type(data)) 23 | if data: 24 | data = 'server echoes: ' + data 25 | cs.send(data) 26 | else: 27 | break 28 | 29 | s.close() 30 | 31 | 32 | def client(ip, port): 33 | s = socket.socket() 34 | s.connect((ip, int(port))) 35 | 36 | for i in range(10): 37 | new_data = data[i:] + data[:i+1] 38 | s.send(new_data) 39 | print s.recv(1000) 40 | sleep(1) 41 | 42 | s.close() 43 | 44 | if __name__ == '__main__': 45 | if sys.argv[1] == 'server': 46 | server(sys.argv[2]) 47 | elif sys.argv[1] == 'client': 48 | client(sys.argv[2], sys.argv[3]) 49 | -------------------------------------------------------------------------------- /15-tcp_stack/tcp_stack_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import os 4 | import sys 5 | import string 6 | import socket 7 | import struct 8 | from time import sleep 9 | 10 | data = string.digits + string.lowercase + string.uppercase 11 | 12 | def server(port, filename): 13 | s = socket.socket() 14 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 15 | 16 | s.bind(('0.0.0.0', int(port))) 17 | s.listen(3) 18 | 19 | cs, addr = s.accept() 20 | print addr 21 | 22 | with open(filename, 'wb') as f: 23 | while True: 24 | data = cs.recv(1024) 25 | if data: 26 | f.write(data) 27 | else: 28 | break 29 | 30 | s.close() 31 | 32 | 33 | def client(ip, port, filename): 34 | s = socket.socket() 35 | s.connect((ip, int(port))) 36 | 37 | file_size = os.path.getsize(filename) 38 | send_size = 0 39 | 40 | with open(filename, 'rb') as f: 41 | while True: 42 | data = f.read(1024) 43 | if data: 44 | send_size += sys.getsizeof(data) 45 | print 'send %d Bytes' % (send_size) 46 | s.send(data) 47 | else: 48 | break 49 | sleep(0.01) 50 | 51 | s.close() 52 | 53 | if __name__ == '__main__': 54 | if sys.argv[1] == 'server': 55 | server(sys.argv[2], sys.argv[3]) 56 | elif sys.argv[1] == 'client': 57 | client(sys.argv[2], sys.argv[3], sys.argv[4]) 58 | -------------------------------------------------------------------------------- /16-tcp_stack/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = tcp_stack 2 | all: $(TARGET) 3 | 4 | CC = gcc 5 | LD = gcc 6 | 7 | CFLAGS = -g -Wall -Iinclude 8 | LDFLAGS = 9 | 10 | LIBS = -lpthread 11 | 12 | HDRS = ./include/*.h 13 | 14 | SRCS = arp.c arpcache.c device_internal.c icmp.c ip_base.c ip.c main.c rtable.c rtable_internal.c \ 15 | tcp.c tcp_apps.c tcp_in.c tcp_out.c tcp_sock.c tcp_timer.c 16 | 17 | OBJS = $(patsubst %.c,%.o,$(SRCS)) 18 | 19 | $(OBJS) : %.o : %.c include/*.h 20 | $(CC) -c $(CFLAGS) $< -o $@ 21 | 22 | $(TARGET): $(OBJS) 23 | $(LD) $(LDFLAGS) $(OBJS) -o $(TARGET) $(LIBS) 24 | 25 | clean: 26 | rm -f *.o $(TARGET) 27 | -------------------------------------------------------------------------------- /16-tcp_stack/create_randfile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dd if=/dev/urandom bs=1MB count=3 | base64 > client-input.dat 4 | -------------------------------------------------------------------------------- /16-tcp_stack/include/arp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARP_H__ 2 | #define __ARP_H__ 3 | 4 | #include "base.h" 5 | #include "ether.h" 6 | #include "types.h" 7 | 8 | #define ARPHRD_ETHER 1 9 | 10 | #define ARPOP_REQUEST 1 11 | #define ARPOP_REPLY 2 12 | 13 | struct ether_arp { 14 | u16 arp_hrd; // format of hardware address, should be 0x01 15 | u16 arp_pro; // format of protocol address, should be 0x0800 16 | u8 arp_hln; // length of hardware address, should be 6 17 | u8 arp_pln; // length of protocol address, should be 4 18 | u16 arp_op; // ARP opcode (command) 19 | u8 arp_sha[ETH_ALEN]; // sender hardware address 20 | u32 arp_spa; // sender protocol address 21 | u8 arp_tha[ETH_ALEN]; // target hardware address 22 | u32 arp_tpa; // target protocol address 23 | } __attribute__ ((packed)); 24 | 25 | // get the arp header of the packet 26 | static inline struct ether_arp *packet_to_ether_arp(const char *packet) 27 | { 28 | return (struct ether_arp *)(packet + ETHER_HDR_SIZE); 29 | } 30 | 31 | void handle_arp_packet(iface_info_t *info, char *packet, int len); 32 | void arp_send_request(iface_info_t *iface, u32 dst_ip); 33 | void iface_send_packet_by_arp(iface_info_t *iface, u32 dst_ip, char *packet, int len); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /16-tcp_stack/include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE_H__ 2 | #define __BASE_H__ 3 | 4 | #include "types.h" 5 | #include "ether.h" 6 | #include "list.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | typedef struct { 28 | struct list_head iface_list; // the list of interfaces 29 | int nifs; // number of interfaces 30 | struct pollfd *fds; // structure used to poll packets among 31 | // all the interfaces 32 | } ustack_t; 33 | 34 | extern ustack_t *instance; 35 | 36 | typedef struct { 37 | struct list_head list; // list node used to link all interfaces 38 | 39 | int fd; // file descriptor for receiving & sending packets 40 | int index; // the index (unique ID) of this interface 41 | u8 mac[ETH_ALEN]; // mac address of this interface 42 | u32 ip; // IPv4 address (in host byte order) 43 | u32 mask; // Network Mask (in host byte order) 44 | char name[16]; // name of this interface 45 | char ip_str[16]; // readable IP address 46 | } iface_info_t; 47 | 48 | void init_ustack(); 49 | iface_info_t *fd_to_iface(int fd); 50 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 51 | #endif 52 | -------------------------------------------------------------------------------- /16-tcp_stack/include/checksum.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHECKSUM_H__ 2 | #define __CHECKSUM_H__ 3 | 4 | #include "types.h" 5 | 6 | // calculate the checksum of the given buf, providing sum 7 | // as the initial value 8 | static inline u16 checksum(void *t_buf, int nbytes, u32 sum) 9 | { 10 | u16 * buf = t_buf; 11 | for (int i = 0; i < nbytes / 2; i++) 12 | sum += buf[i]; 13 | 14 | if (nbytes % 2) 15 | sum += ((u8 *)buf)[nbytes-1]; 16 | 17 | while (sum >> 16) 18 | sum = (sum >> 16) + (sum & 0xffff); 19 | 20 | return (u16)~sum; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /16-tcp_stack/include/ether.h: -------------------------------------------------------------------------------- 1 | #ifndef __ETHER_H__ 2 | #define __ETHER_H__ 3 | 4 | #include "types.h" 5 | 6 | #define ETH_ALEN 6 // length of mac address 7 | #define ETH_FRAME_LEN 1514 // maximum length of an ethernet frame (packet) 8 | 9 | // protocol format in ethernet header 10 | #define ETH_P_ALL 0x0003 // every packet, only used when tending to receive all packets 11 | #define ETH_P_IP 0x0800 // IP packet 12 | #define ETH_P_ARP 0x0806 // ARP packet 13 | 14 | struct ether_header { 15 | u8 ether_dhost[ETH_ALEN]; // destination mac address 16 | u8 ether_shost[ETH_ALEN]; // source mac address 17 | u16 ether_type; // protocol format 18 | }; 19 | 20 | #define ETHER_HDR_SIZE sizeof(struct ether_header) 21 | 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /16-tcp_stack/include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __HASH_H__ 2 | #define __HASH_H__ 3 | 4 | #include "types.h" 5 | 6 | #define HASH_8BITS 256 7 | #define HASH_16BITS 65536 8 | 9 | // the simplest hash functions, you can recreate the wheels as you wish 10 | 11 | static inline u8 hash8(char *buf, int len) 12 | { 13 | u8 result = 0; 14 | for (int i = 0; i < len; i++) 15 | result ^= buf[i]; 16 | 17 | return result; 18 | } 19 | 20 | static inline u16 hash16(char *buf, int len) 21 | { 22 | u16 result = 0; 23 | for (int i = 0; i < len / 2 * 2; i += 2) 24 | result ^= *(u16 *)(buf + i); 25 | 26 | if (len % 2) 27 | result ^= (u8)(buf[len-1]); 28 | 29 | return result; 30 | } 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /16-tcp_stack/include/icmp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ICMP_H__ 2 | #define __ICMP_H__ 3 | 4 | #include "types.h" 5 | #include "checksum.h" 6 | #include "base.h" 7 | 8 | struct icmphdr { 9 | u8 type; // type of icmp message 10 | u8 code; // icmp code 11 | u16 checksum; 12 | u16 icmp_identifier; // icmp identifier, used in icmp echo request 13 | u16 icmp_sequence; // icmp sequence, used in icmp echo request 14 | }__attribute__((packed)); 15 | 16 | #define ICMP_HDR_SIZE sizeof(struct icmphdr) 17 | #define ICMP_COPIED_DATA_LEN 8 18 | 19 | #define ICMP_ECHOREQUEST 8 // echo request 20 | #define ICMP_ECHOREPLY 0 // echo reply 21 | #define ICMP_DEST_UNREACH 3 // destination unreachable 22 | #define ICMP_TIME_EXCEEDED 11 // time exceeded 23 | 24 | // codes for UNREACH 25 | #define ICMP_NET_UNREACH 0 // network unreachable 26 | #define ICMP_HOST_UNREACH 1 // host unreachable 27 | 28 | // code for TIME_EXCEEDED 29 | #define ICMP_EXC_TTL 0 // ttl count exceeded 30 | 31 | // calculate the checksum of icmp data, note that the length of icmp data varies 32 | static inline u16 icmp_checksum(struct icmphdr *icmp, int len) 33 | { 34 | u16 tmp = icmp->checksum; 35 | icmp->checksum = 0; 36 | u16 sum = checksum((u16 *)icmp, len, 0); 37 | icmp->checksum = tmp; 38 | 39 | return sum; 40 | } 41 | 42 | // construct icmp packet according to type, code and incoming packet, and send it 43 | void icmp_send_packet(const char *in_pkt, int len, u8 type, u8 code); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /16-tcp_stack/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // #define LOG_DEBUG 9 | 10 | enum log_level { DEBUG = 0, INFO, WARNING, ERROR }; 11 | 12 | static enum log_level this_log_level = DEBUG; 13 | 14 | static const char *log_level_str[] = { "DEBUG", "INFO", "WARNING", "ERROR" }; 15 | 16 | #ifdef LOG_DEBUG 17 | #define log_it(fmt, level_str, ...) \ 18 | fprintf(stderr, "[%s:%u] %s: " fmt "\n", __FILE__, __LINE__, \ 19 | level_str, ##__VA_ARGS__); 20 | #else 21 | #define log_it(fmt, level_str, ...) \ 22 | fprintf(stderr, "%s: " fmt "\n", level_str, ##__VA_ARGS__); 23 | #endif 24 | 25 | #define log(level, fmt, ...) \ 26 | do { \ 27 | if (level < this_log_level) \ 28 | break; \ 29 | log_it(fmt, log_level_str[level], ##__VA_ARGS__); \ 30 | } while (0) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /16-tcp_stack/include/packet.h: -------------------------------------------------------------------------------- 1 | #ifndef __PACKET_H__ 2 | #define __PACKET_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 8 | void broadcast_packet(iface_info_t *iface, char *packet, int len); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /16-tcp_stack/include/rtable.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTABLE_H__ 2 | #define __RTABLE_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | #include "list.h" 8 | 9 | // structure of ip forwarding table 10 | // note: 1, the table supports only ipv4 address; 11 | // 2, addresses are stored in host byte order. 12 | typedef struct { 13 | struct list_head list; 14 | u32 dest; // destination ip address (could be network or host) 15 | u32 mask; // network mask of dest 16 | u32 gw; // ip address of next hop (will be 0 if dest is in 17 | // the same network with iface) 18 | int flags; // flags (could be omitted here) 19 | char if_name[16]; // name of the interface 20 | iface_info_t *iface; // pointer to the interface structure 21 | } rt_entry_t; 22 | 23 | extern struct list_head rtable; 24 | 25 | void init_rtable(); 26 | void load_static_rtable(); 27 | void clear_rtable(); 28 | void add_rt_entry(rt_entry_t *entry); 29 | void remove_rt_entry(rt_entry_t *entry); 30 | void print_rtable(); 31 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface); 32 | 33 | rt_entry_t *longest_prefix_match(u32 ip); 34 | u32 get_next_hop(rt_entry_t *entry, u32 dst); 35 | 36 | void load_rtable_from_kernel(); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /16-tcp_stack/include/tcp_apps.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_APPS_H__ 2 | #define __TCP_APPS_H__ 3 | 4 | extern char filename[100]; 5 | 6 | void *tcp_server(void *arg); 7 | void *tcp_client(void *arg); 8 | 9 | void *tcp_server_file(void *arg); 10 | void *tcp_client_file(void *arg); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /16-tcp_stack/include/tcp_hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_HASH_H__ 2 | #define __TCP_HASH_H__ 3 | 4 | #include "hash.h" 5 | #include "list.h" 6 | #include "tcp_sock.h" 7 | 8 | #define TCP_HASH_SIZE HASH_8BITS 9 | #define TCP_HASH_MASK (TCP_HASH_SIZE - 1) 10 | 11 | // the 3 tables in tcp_hash_table 12 | struct tcp_hash_table { 13 | struct list_head established_table[TCP_HASH_SIZE]; 14 | struct list_head listen_table[TCP_HASH_SIZE]; 15 | struct list_head bind_table[TCP_HASH_SIZE]; 16 | }; 17 | 18 | // tcp hash function: if hashed into bind_table or listen_table, only use sport; 19 | // otherwise, use all the 4 arguments 20 | static inline int tcp_hash_function(u32 saddr, u32 daddr, u16 sport, u16 dport) 21 | { 22 | int result = hash8((char *)&saddr, 4) ^ hash8((char *)&daddr, 4) ^ \ 23 | hash8((char *)&sport, 2) ^ hash8((char *)&dport, 2); 24 | 25 | return result & TCP_HASH_MASK; 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /16-tcp_stack/include/tcp_timer.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_TIMER_H__ 2 | #define __TCP_TIMER_H__ 3 | 4 | #include "list.h" 5 | 6 | #include 7 | 8 | struct tcp_timer { 9 | int type; // time-wait: 0 retrans: 1 10 | #define TIMER_TYPE_TIME_WAIT 0 11 | #define TIMER_TYPE_RETRANS 1 12 | 13 | int timeout; // in micro second 14 | struct list_head list; 15 | int enable; 16 | }; 17 | 18 | struct tcp_sock; 19 | #define timewait_to_tcp_sock(t) \ 20 | (struct tcp_sock *)((char *)(t) - offsetof(struct tcp_sock, timewait)) 21 | 22 | #define retranstimer_to_tcp_sock(t) \ 23 | (struct tcp_sock *)((char *)(t) - offsetof(struct tcp_sock, retrans_timer)) 24 | #define TCP_TIMER_SCAN_INTERVAL 100000 25 | #define TCP_MSL 1000000 26 | #define TCP_TIMEWAIT_TIMEOUT (2 * TCP_MSL) 27 | #define TCP_RETRANS_INTERVAL_INITIAL 200000 28 | 29 | // init sources of tcp_timer 30 | void tcp_timer_init(); 31 | // the thread that scans timer_list periodically 32 | void *tcp_timer_thread(void *arg); 33 | // add the timer of tcp sock to timer_list 34 | void tcp_set_timewait_timer(struct tcp_sock *); 35 | 36 | void tcp_set_retrans_timer(struct tcp_sock *tsk); 37 | int tcp_update_retrans_timer(struct tcp_sock *tsk, int retrans_times); 38 | void tcp_unset_retrans_timer(struct tcp_sock *tsk); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /16-tcp_stack/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | 6 | typedef uint8_t u8; 7 | typedef uint16_t u16; 8 | typedef uint32_t u32; 9 | typedef uint64_t u64; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /16-tcp_stack/ip.c: -------------------------------------------------------------------------------- 1 | #include "ip.h" 2 | #include "icmp.h" 3 | #include "arpcache.h" 4 | #include "rtable.h" 5 | #include "arp.h" 6 | #include "tcp.h" 7 | 8 | #include "log.h" 9 | 10 | #include 11 | 12 | 13 | void handle_ip_packet(iface_info_t *iface, char *packet, int len) 14 | { 15 | struct iphdr *ip = packet_to_ip_hdr(packet); 16 | u32 daddr = ntohl(ip->daddr); 17 | if (daddr == iface->ip) { 18 | if (ip->protocol == IPPROTO_ICMP) { 19 | struct icmphdr *icmp = (struct icmphdr *)IP_DATA(ip); 20 | if (icmp->type == ICMP_ECHOREQUEST) { 21 | icmp_send_packet(packet, len, ICMP_ECHOREPLY, 0); 22 | } 23 | } 24 | else if (ip->protocol == IPPROTO_TCP) { 25 | handle_tcp_packet(packet, ip, (struct tcphdr *)(IP_DATA(ip))); 26 | } 27 | else { 28 | log(ERROR, "unsupported IP protocol (0x%x) packet.", ip->protocol); 29 | } 30 | 31 | free(packet); 32 | } 33 | else { 34 | // ip_forward_packet(daddr, packet, len); 35 | log(ERROR, "received packet with incorrect destination IP address."); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /16-tcp_stack/rtable.c: -------------------------------------------------------------------------------- 1 | #include "rtable.h" 2 | #include "ip.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct list_head rtable; 9 | 10 | void init_rtable() 11 | { 12 | init_list_head(&rtable); 13 | } 14 | 15 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface) 16 | { 17 | rt_entry_t *entry = malloc(sizeof(*entry)); 18 | memset(entry, 0, sizeof(*entry)); 19 | 20 | init_list_head(&(entry->list)); 21 | entry->dest = dest; 22 | entry->mask = mask; 23 | entry->gw = gw; 24 | entry->iface = iface; 25 | strcpy(entry->if_name, iface->name); 26 | 27 | return entry; 28 | } 29 | 30 | void add_rt_entry(rt_entry_t *entry) 31 | { 32 | list_add_tail(&entry->list, &rtable); 33 | } 34 | 35 | void remove_rt_entry(rt_entry_t *entry) 36 | { 37 | list_delete_entry(&entry->list); 38 | free(entry); 39 | } 40 | 41 | void clear_rtable() 42 | { 43 | struct list_head *head = &rtable, *tmp; 44 | while (head->next != head) { 45 | tmp = head->next; 46 | list_delete_entry(tmp); 47 | rt_entry_t *entry = list_entry(tmp, rt_entry_t, list); 48 | free(entry); 49 | } 50 | } 51 | 52 | void print_rtable() 53 | { 54 | // Print the routing table 55 | fprintf(stdout, "Routing Table:\n"); 56 | fprintf(stdout, "dest\tmask\tgateway\tif_name\n"); 57 | fprintf(stdout, "--------------------------------------\n"); 58 | rt_entry_t *entry = NULL; 59 | list_for_each_entry(entry, &rtable, list) { 60 | fprintf(stdout, IP_FMT"\t"IP_FMT"\t"IP_FMT"\t%s\n", \ 61 | HOST_IP_FMT_STR(entry->dest), \ 62 | HOST_IP_FMT_STR(entry->mask), \ 63 | HOST_IP_FMT_STR(entry->gw), \ 64 | entry->if_name); 65 | } 66 | fprintf(stdout, "--------------------------------------\n"); 67 | } 68 | -------------------------------------------------------------------------------- /16-tcp_stack/scripts/disable_arp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | arptables -A FORWARD -j DROP 4 | arptables -A OUTPUT -j DROP 5 | -------------------------------------------------------------------------------- /16-tcp_stack/scripts/disable_icmp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p icmp --icmp-type echo-request -j DROP 4 | iptables -A OUTPUT -p icmp --icmp-type echo-reply -j DROP 5 | iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP 6 | -------------------------------------------------------------------------------- /16-tcp_stack/scripts/disable_ip_forward.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p ip -j DROP 4 | echo 0 > /proc/sys/net/ipv4/ip_forward 5 | -------------------------------------------------------------------------------- /16-tcp_stack/scripts/disable_ipv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w net.ipv6.conf.all.disable_ipv6=1 4 | sysctl -w net.ipv6.conf.default.disable_ipv6=1 5 | -------------------------------------------------------------------------------- /16-tcp_stack/scripts/disable_offloading.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The virtual NIC does not support "lro rxhash" options. 4 | TOE_OPTIONS="rx tx sg tso ufo gso gro rxvlan txvlan" 5 | 6 | for IFACE in `/sbin/ifconfig | grep '^.*-eth[0-9]' | awk '{print $1}'`; do 7 | echo "Disabling $IFACE ..." 8 | for TOE_OPTION in $TOE_OPTIONS; do 9 | /sbin/ethtool --offload "$IFACE" "$TOE_OPTION" off 10 | done 11 | done 12 | -------------------------------------------------------------------------------- /16-tcp_stack/scripts/disable_tcp_rst.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP 4 | -------------------------------------------------------------------------------- /16-tcp_stack/tcp_stack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import sys 4 | import string 5 | import socket 6 | from time import sleep 7 | 8 | data = string.digits + string.lowercase + string.uppercase 9 | 10 | def server(port): 11 | s = socket.socket() 12 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 13 | 14 | s.bind(('0.0.0.0', int(port))) 15 | s.listen(3) 16 | 17 | cs, addr = s.accept() 18 | print addr 19 | 20 | while True: 21 | data = cs.recv(1000) 22 | print(type(data)) 23 | if data: 24 | data = 'server echoes: ' + data 25 | cs.send(data) 26 | else: 27 | break 28 | 29 | s.close() 30 | 31 | 32 | def client(ip, port): 33 | s = socket.socket() 34 | s.connect((ip, int(port))) 35 | 36 | for i in range(10): 37 | new_data = data[i:] + data[:i+1] 38 | s.send(new_data) 39 | print s.recv(1000) 40 | sleep(1) 41 | 42 | s.close() 43 | 44 | if __name__ == '__main__': 45 | if sys.argv[1] == 'server': 46 | server(sys.argv[2]) 47 | elif sys.argv[1] == 'client': 48 | client(sys.argv[2], sys.argv[3]) 49 | -------------------------------------------------------------------------------- /16-tcp_stack/tcp_stack_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import os 4 | import sys 5 | import string 6 | import socket 7 | import struct 8 | from time import sleep 9 | 10 | data = string.digits + string.lowercase + string.uppercase 11 | 12 | def server(port, filename): 13 | s = socket.socket() 14 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 15 | 16 | s.bind(('0.0.0.0', int(port))) 17 | s.listen(3) 18 | 19 | cs, addr = s.accept() 20 | print addr 21 | 22 | with open(filename, 'wb') as f: 23 | while True: 24 | data = cs.recv(1024) 25 | if data: 26 | f.write(data) 27 | else: 28 | break 29 | 30 | s.close() 31 | 32 | 33 | def client(ip, port, filename): 34 | s = socket.socket() 35 | s.connect((ip, int(port))) 36 | 37 | file_size = os.path.getsize(filename) 38 | send_size = 0 39 | 40 | with open(filename, 'rb') as f: 41 | while True: 42 | data = f.read(1024) 43 | if data: 44 | send_size += sys.getsizeof(data) 45 | print 'send %d Bytes' % (send_size) 46 | s.send(data) 47 | else: 48 | break 49 | sleep(0.01) 50 | 51 | s.close() 52 | 53 | if __name__ == '__main__': 54 | if sys.argv[1] == 'server': 55 | server(sys.argv[2], sys.argv[3]) 56 | elif sys.argv[1] == 'client': 57 | client(sys.argv[2], sys.argv[3], sys.argv[4]) 58 | -------------------------------------------------------------------------------- /17-tcp_stack/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = tcp_stack 2 | all: $(TARGET) 3 | 4 | CC = gcc 5 | LD = gcc 6 | 7 | CFLAGS = -g -Wall -Iinclude 8 | LDFLAGS = 9 | 10 | LIBS = -lpthread 11 | 12 | HDRS = ./include/*.h 13 | 14 | SRCS = arp.c arpcache.c device_internal.c icmp.c ip_base.c ip.c main.c rtable.c rtable_internal.c \ 15 | tcp.c tcp_apps.c tcp_in.c tcp_out.c tcp_sock.c tcp_timer.c 16 | 17 | OBJS = $(patsubst %.c,%.o,$(SRCS)) 18 | 19 | $(OBJS) : %.o : %.c include/*.h 20 | $(CC) -c $(CFLAGS) $< -o $@ 21 | 22 | $(TARGET): $(OBJS) 23 | $(LD) $(LDFLAGS) $(OBJS) -o $(TARGET) $(LIBS) 24 | 25 | clean: 26 | rm -f *.o $(TARGET) 27 | -------------------------------------------------------------------------------- /17-tcp_stack/create_randfile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dd if=/dev/urandom bs=1MB count=3 | base64 > client-input.dat 4 | -------------------------------------------------------------------------------- /17-tcp_stack/include/arp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARP_H__ 2 | #define __ARP_H__ 3 | 4 | #include "base.h" 5 | #include "ether.h" 6 | #include "types.h" 7 | 8 | #define ARPHRD_ETHER 1 9 | 10 | #define ARPOP_REQUEST 1 11 | #define ARPOP_REPLY 2 12 | 13 | struct ether_arp { 14 | u16 arp_hrd; // format of hardware address, should be 0x01 15 | u16 arp_pro; // format of protocol address, should be 0x0800 16 | u8 arp_hln; // length of hardware address, should be 6 17 | u8 arp_pln; // length of protocol address, should be 4 18 | u16 arp_op; // ARP opcode (command) 19 | u8 arp_sha[ETH_ALEN]; // sender hardware address 20 | u32 arp_spa; // sender protocol address 21 | u8 arp_tha[ETH_ALEN]; // target hardware address 22 | u32 arp_tpa; // target protocol address 23 | } __attribute__ ((packed)); 24 | 25 | // get the arp header of the packet 26 | static inline struct ether_arp *packet_to_ether_arp(const char *packet) 27 | { 28 | return (struct ether_arp *)(packet + ETHER_HDR_SIZE); 29 | } 30 | 31 | void handle_arp_packet(iface_info_t *info, char *packet, int len); 32 | void arp_send_request(iface_info_t *iface, u32 dst_ip); 33 | void iface_send_packet_by_arp(iface_info_t *iface, u32 dst_ip, char *packet, int len); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /17-tcp_stack/include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE_H__ 2 | #define __BASE_H__ 3 | 4 | #include "types.h" 5 | #include "ether.h" 6 | #include "list.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | typedef struct { 28 | struct list_head iface_list; // the list of interfaces 29 | int nifs; // number of interfaces 30 | struct pollfd *fds; // structure used to poll packets among 31 | // all the interfaces 32 | } ustack_t; 33 | 34 | extern ustack_t *instance; 35 | 36 | typedef struct { 37 | struct list_head list; // list node used to link all interfaces 38 | 39 | int fd; // file descriptor for receiving & sending packets 40 | int index; // the index (unique ID) of this interface 41 | u8 mac[ETH_ALEN]; // mac address of this interface 42 | u32 ip; // IPv4 address (in host byte order) 43 | u32 mask; // Network Mask (in host byte order) 44 | char name[16]; // name of this interface 45 | char ip_str[16]; // readable IP address 46 | } iface_info_t; 47 | 48 | void init_ustack(); 49 | iface_info_t *fd_to_iface(int fd); 50 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 51 | #endif 52 | -------------------------------------------------------------------------------- /17-tcp_stack/include/checksum.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHECKSUM_H__ 2 | #define __CHECKSUM_H__ 3 | 4 | #include "types.h" 5 | 6 | // calculate the checksum of the given buf, providing sum 7 | // as the initial value 8 | static inline u16 checksum(void *t_buf, int nbytes, u32 sum) 9 | { 10 | u16 * buf = t_buf; 11 | for (int i = 0; i < nbytes / 2; i++) 12 | sum += buf[i]; 13 | 14 | if (nbytes % 2) 15 | sum += ((u8 *)buf)[nbytes-1]; 16 | 17 | while (sum >> 16) 18 | sum = (sum >> 16) + (sum & 0xffff); 19 | 20 | return (u16)~sum; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /17-tcp_stack/include/ether.h: -------------------------------------------------------------------------------- 1 | #ifndef __ETHER_H__ 2 | #define __ETHER_H__ 3 | 4 | #include "types.h" 5 | 6 | #define ETH_ALEN 6 // length of mac address 7 | #define ETH_FRAME_LEN 1514 // maximum length of an ethernet frame (packet) 8 | 9 | // protocol format in ethernet header 10 | #define ETH_P_ALL 0x0003 // every packet, only used when tending to receive all packets 11 | #define ETH_P_IP 0x0800 // IP packet 12 | #define ETH_P_ARP 0x0806 // ARP packet 13 | 14 | struct ether_header { 15 | u8 ether_dhost[ETH_ALEN]; // destination mac address 16 | u8 ether_shost[ETH_ALEN]; // source mac address 17 | u16 ether_type; // protocol format 18 | }; 19 | 20 | #define ETHER_HDR_SIZE sizeof(struct ether_header) 21 | 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /17-tcp_stack/include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __HASH_H__ 2 | #define __HASH_H__ 3 | 4 | #include "types.h" 5 | 6 | #define HASH_8BITS 256 7 | #define HASH_16BITS 65536 8 | 9 | // the simplest hash functions, you can recreate the wheels as you wish 10 | 11 | static inline u8 hash8(char *buf, int len) 12 | { 13 | u8 result = 0; 14 | for (int i = 0; i < len; i++) 15 | result ^= buf[i]; 16 | 17 | return result; 18 | } 19 | 20 | static inline u16 hash16(char *buf, int len) 21 | { 22 | u16 result = 0; 23 | for (int i = 0; i < len / 2 * 2; i += 2) 24 | result ^= *(u16 *)(buf + i); 25 | 26 | if (len % 2) 27 | result ^= (u8)(buf[len-1]); 28 | 29 | return result; 30 | } 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /17-tcp_stack/include/icmp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ICMP_H__ 2 | #define __ICMP_H__ 3 | 4 | #include "types.h" 5 | #include "checksum.h" 6 | #include "base.h" 7 | 8 | struct icmphdr { 9 | u8 type; // type of icmp message 10 | u8 code; // icmp code 11 | u16 checksum; 12 | u16 icmp_identifier; // icmp identifier, used in icmp echo request 13 | u16 icmp_sequence; // icmp sequence, used in icmp echo request 14 | }__attribute__((packed)); 15 | 16 | #define ICMP_HDR_SIZE sizeof(struct icmphdr) 17 | #define ICMP_COPIED_DATA_LEN 8 18 | 19 | #define ICMP_ECHOREQUEST 8 // echo request 20 | #define ICMP_ECHOREPLY 0 // echo reply 21 | #define ICMP_DEST_UNREACH 3 // destination unreachable 22 | #define ICMP_TIME_EXCEEDED 11 // time exceeded 23 | 24 | // codes for UNREACH 25 | #define ICMP_NET_UNREACH 0 // network unreachable 26 | #define ICMP_HOST_UNREACH 1 // host unreachable 27 | 28 | // code for TIME_EXCEEDED 29 | #define ICMP_EXC_TTL 0 // ttl count exceeded 30 | 31 | // calculate the checksum of icmp data, note that the length of icmp data varies 32 | static inline u16 icmp_checksum(struct icmphdr *icmp, int len) 33 | { 34 | u16 tmp = icmp->checksum; 35 | icmp->checksum = 0; 36 | u16 sum = checksum((u16 *)icmp, len, 0); 37 | icmp->checksum = tmp; 38 | 39 | return sum; 40 | } 41 | 42 | // construct icmp packet according to type, code and incoming packet, and send it 43 | void icmp_send_packet(const char *in_pkt, int len, u8 type, u8 code); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /17-tcp_stack/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // #define LOG_DEBUG 9 | 10 | enum log_level { DEBUG = 0, INFO, WARNING, ERROR }; 11 | 12 | static enum log_level this_log_level = DEBUG; 13 | 14 | static const char *log_level_str[] = { "DEBUG", "INFO", "WARNING", "ERROR" }; 15 | 16 | #ifdef LOG_DEBUG 17 | #define log_it(fmt, level_str, ...) \ 18 | fprintf(stderr, "[%s:%u] %s: " fmt "\n", __FILE__, __LINE__, \ 19 | level_str, ##__VA_ARGS__); 20 | #else 21 | #define log_it(fmt, level_str, ...) \ 22 | fprintf(stderr, "%s: " fmt "\n", level_str, ##__VA_ARGS__); 23 | #endif 24 | 25 | #define log(level, fmt, ...) \ 26 | do { \ 27 | if (level < this_log_level) \ 28 | break; \ 29 | log_it(fmt, log_level_str[level], ##__VA_ARGS__); \ 30 | } while (0) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /17-tcp_stack/include/packet.h: -------------------------------------------------------------------------------- 1 | #ifndef __PACKET_H__ 2 | #define __PACKET_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 8 | void broadcast_packet(iface_info_t *iface, char *packet, int len); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /17-tcp_stack/include/rtable.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTABLE_H__ 2 | #define __RTABLE_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | #include "list.h" 8 | 9 | // structure of ip forwarding table 10 | // note: 1, the table supports only ipv4 address; 11 | // 2, addresses are stored in host byte order. 12 | typedef struct { 13 | struct list_head list; 14 | u32 dest; // destination ip address (could be network or host) 15 | u32 mask; // network mask of dest 16 | u32 gw; // ip address of next hop (will be 0 if dest is in 17 | // the same network with iface) 18 | int flags; // flags (could be omitted here) 19 | char if_name[16]; // name of the interface 20 | iface_info_t *iface; // pointer to the interface structure 21 | } rt_entry_t; 22 | 23 | extern struct list_head rtable; 24 | 25 | void init_rtable(); 26 | void load_static_rtable(); 27 | void clear_rtable(); 28 | void add_rt_entry(rt_entry_t *entry); 29 | void remove_rt_entry(rt_entry_t *entry); 30 | void print_rtable(); 31 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface); 32 | 33 | rt_entry_t *longest_prefix_match(u32 ip); 34 | u32 get_next_hop(rt_entry_t *entry, u32 dst); 35 | 36 | void load_rtable_from_kernel(); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /17-tcp_stack/include/tcp_apps.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_APPS_H__ 2 | #define __TCP_APPS_H__ 3 | 4 | extern char filename[100]; 5 | 6 | void *tcp_server(void *arg); 7 | void *tcp_client(void *arg); 8 | 9 | void *tcp_server_file(void *arg); 10 | void *tcp_client_file(void *arg); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /17-tcp_stack/include/tcp_hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_HASH_H__ 2 | #define __TCP_HASH_H__ 3 | 4 | #include "hash.h" 5 | #include "list.h" 6 | #include "tcp_sock.h" 7 | 8 | #define TCP_HASH_SIZE HASH_8BITS 9 | #define TCP_HASH_MASK (TCP_HASH_SIZE - 1) 10 | 11 | // the 3 tables in tcp_hash_table 12 | struct tcp_hash_table { 13 | struct list_head established_table[TCP_HASH_SIZE]; 14 | struct list_head listen_table[TCP_HASH_SIZE]; 15 | struct list_head bind_table[TCP_HASH_SIZE]; 16 | }; 17 | 18 | // tcp hash function: if hashed into bind_table or listen_table, only use sport; 19 | // otherwise, use all the 4 arguments 20 | static inline int tcp_hash_function(u32 saddr, u32 daddr, u16 sport, u16 dport) 21 | { 22 | int result = hash8((char *)&saddr, 4) ^ hash8((char *)&daddr, 4) ^ \ 23 | hash8((char *)&sport, 2) ^ hash8((char *)&dport, 2); 24 | 25 | return result & TCP_HASH_MASK; 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /17-tcp_stack/include/tcp_timer.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_TIMER_H__ 2 | #define __TCP_TIMER_H__ 3 | 4 | #include "list.h" 5 | 6 | #include 7 | 8 | struct tcp_timer { 9 | int type; // time-wait: 0 retrans: 1 10 | #define TIMER_TYPE_TIME_WAIT 0 11 | #define TIMER_TYPE_RETRANS 1 12 | 13 | int timeout; // in micro second 14 | struct list_head list; 15 | int enable; 16 | }; 17 | 18 | struct tcp_sock; 19 | #define timewait_to_tcp_sock(t) \ 20 | (struct tcp_sock *)((char *)(t) - offsetof(struct tcp_sock, timewait)) 21 | 22 | #define retranstimer_to_tcp_sock(t) \ 23 | (struct tcp_sock *)((char *)(t) - offsetof(struct tcp_sock, retrans_timer)) 24 | #define TCP_TIMER_SCAN_INTERVAL 100000 25 | #define TCP_MSL 1000000 26 | #define TCP_TIMEWAIT_TIMEOUT (2 * TCP_MSL) 27 | #define TCP_RETRANS_INTERVAL_INITIAL 200000 28 | 29 | // init sources of tcp_timer 30 | void tcp_timer_init(); 31 | // the thread that scans timer_list periodically 32 | void *tcp_timer_thread(void *arg); 33 | // add the timer of tcp sock to timer_list 34 | void tcp_set_timewait_timer(struct tcp_sock *); 35 | 36 | void tcp_set_retrans_timer(struct tcp_sock *tsk); 37 | int tcp_update_retrans_timer(struct tcp_sock *tsk, int retrans_times); 38 | void tcp_unset_retrans_timer(struct tcp_sock *tsk); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /17-tcp_stack/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | 6 | typedef uint8_t u8; 7 | typedef uint16_t u16; 8 | typedef uint32_t u32; 9 | typedef uint64_t u64; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /17-tcp_stack/ip.c: -------------------------------------------------------------------------------- 1 | #include "ip.h" 2 | #include "icmp.h" 3 | #include "arpcache.h" 4 | #include "rtable.h" 5 | #include "arp.h" 6 | #include "tcp.h" 7 | 8 | #include "log.h" 9 | 10 | #include 11 | 12 | 13 | void handle_ip_packet(iface_info_t *iface, char *packet, int len) 14 | { 15 | struct iphdr *ip = packet_to_ip_hdr(packet); 16 | u32 daddr = ntohl(ip->daddr); 17 | if (daddr == iface->ip) { 18 | if (ip->protocol == IPPROTO_ICMP) { 19 | struct icmphdr *icmp = (struct icmphdr *)IP_DATA(ip); 20 | if (icmp->type == ICMP_ECHOREQUEST) { 21 | icmp_send_packet(packet, len, ICMP_ECHOREPLY, 0); 22 | } 23 | } 24 | else if (ip->protocol == IPPROTO_TCP) { 25 | handle_tcp_packet(packet, ip, (struct tcphdr *)(IP_DATA(ip))); 26 | } 27 | else { 28 | log(ERROR, "unsupported IP protocol (0x%x) packet.", ip->protocol); 29 | } 30 | 31 | free(packet); 32 | } 33 | else { 34 | // ip_forward_packet(daddr, packet, len); 35 | log(ERROR, "received packet with incorrect destination IP address."); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /17-tcp_stack/rtable.c: -------------------------------------------------------------------------------- 1 | #include "rtable.h" 2 | #include "ip.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct list_head rtable; 9 | 10 | void init_rtable() 11 | { 12 | init_list_head(&rtable); 13 | } 14 | 15 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface) 16 | { 17 | rt_entry_t *entry = malloc(sizeof(*entry)); 18 | memset(entry, 0, sizeof(*entry)); 19 | 20 | init_list_head(&(entry->list)); 21 | entry->dest = dest; 22 | entry->mask = mask; 23 | entry->gw = gw; 24 | entry->iface = iface; 25 | strcpy(entry->if_name, iface->name); 26 | 27 | return entry; 28 | } 29 | 30 | void add_rt_entry(rt_entry_t *entry) 31 | { 32 | list_add_tail(&entry->list, &rtable); 33 | } 34 | 35 | void remove_rt_entry(rt_entry_t *entry) 36 | { 37 | list_delete_entry(&entry->list); 38 | free(entry); 39 | } 40 | 41 | void clear_rtable() 42 | { 43 | struct list_head *head = &rtable, *tmp; 44 | while (head->next != head) { 45 | tmp = head->next; 46 | list_delete_entry(tmp); 47 | rt_entry_t *entry = list_entry(tmp, rt_entry_t, list); 48 | free(entry); 49 | } 50 | } 51 | 52 | void print_rtable() 53 | { 54 | // Print the routing table 55 | fprintf(stdout, "Routing Table:\n"); 56 | fprintf(stdout, "dest\tmask\tgateway\tif_name\n"); 57 | fprintf(stdout, "--------------------------------------\n"); 58 | rt_entry_t *entry = NULL; 59 | list_for_each_entry(entry, &rtable, list) { 60 | fprintf(stdout, IP_FMT"\t"IP_FMT"\t"IP_FMT"\t%s\n", \ 61 | HOST_IP_FMT_STR(entry->dest), \ 62 | HOST_IP_FMT_STR(entry->mask), \ 63 | HOST_IP_FMT_STR(entry->gw), \ 64 | entry->if_name); 65 | } 66 | fprintf(stdout, "--------------------------------------\n"); 67 | } 68 | -------------------------------------------------------------------------------- /17-tcp_stack/scripts/disable_arp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | arptables -A FORWARD -j DROP 4 | arptables -A OUTPUT -j DROP 5 | -------------------------------------------------------------------------------- /17-tcp_stack/scripts/disable_icmp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p icmp --icmp-type echo-request -j DROP 4 | iptables -A OUTPUT -p icmp --icmp-type echo-reply -j DROP 5 | iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP 6 | -------------------------------------------------------------------------------- /17-tcp_stack/scripts/disable_ip_forward.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p ip -j DROP 4 | echo 0 > /proc/sys/net/ipv4/ip_forward 5 | -------------------------------------------------------------------------------- /17-tcp_stack/scripts/disable_ipv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w net.ipv6.conf.all.disable_ipv6=1 4 | sysctl -w net.ipv6.conf.default.disable_ipv6=1 5 | -------------------------------------------------------------------------------- /17-tcp_stack/scripts/disable_offloading.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The virtual NIC does not support "lro rxhash" options. 4 | TOE_OPTIONS="rx tx sg tso ufo gso gro rxvlan txvlan" 5 | 6 | for IFACE in `/sbin/ifconfig | grep '^.*-eth[0-9]' | awk '{print $1}'`; do 7 | echo "Disabling $IFACE ..." 8 | for TOE_OPTION in $TOE_OPTIONS; do 9 | /sbin/ethtool --offload "$IFACE" "$TOE_OPTION" off 10 | done 11 | done 12 | -------------------------------------------------------------------------------- /17-tcp_stack/scripts/disable_tcp_rst.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP 4 | -------------------------------------------------------------------------------- /17-tcp_stack/tcp_stack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import sys 4 | import string 5 | import socket 6 | from time import sleep 7 | 8 | data = string.digits + string.lowercase + string.uppercase 9 | 10 | def server(port): 11 | s = socket.socket() 12 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 13 | 14 | s.bind(('0.0.0.0', int(port))) 15 | s.listen(3) 16 | 17 | cs, addr = s.accept() 18 | print addr 19 | 20 | while True: 21 | data = cs.recv(1000) 22 | print(type(data)) 23 | if data: 24 | data = 'server echoes: ' + data 25 | cs.send(data) 26 | else: 27 | break 28 | 29 | s.close() 30 | 31 | 32 | def client(ip, port): 33 | s = socket.socket() 34 | s.connect((ip, int(port))) 35 | 36 | for i in range(10): 37 | new_data = data[i:] + data[:i+1] 38 | s.send(new_data) 39 | print s.recv(1000) 40 | sleep(1) 41 | 42 | s.close() 43 | 44 | if __name__ == '__main__': 45 | if sys.argv[1] == 'server': 46 | server(sys.argv[2]) 47 | elif sys.argv[1] == 'client': 48 | client(sys.argv[2], sys.argv[3]) 49 | -------------------------------------------------------------------------------- /17-tcp_stack/tcp_stack_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import os 4 | import sys 5 | import string 6 | import socket 7 | import struct 8 | from time import sleep 9 | 10 | data = string.digits + string.lowercase + string.uppercase 11 | 12 | def server(port, filename): 13 | s = socket.socket() 14 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 15 | 16 | s.bind(('0.0.0.0', int(port))) 17 | s.listen(3) 18 | 19 | cs, addr = s.accept() 20 | print addr 21 | 22 | with open(filename, 'wb') as f: 23 | while True: 24 | data = cs.recv(1024) 25 | if data: 26 | f.write(data) 27 | else: 28 | break 29 | 30 | s.close() 31 | 32 | 33 | def client(ip, port, filename): 34 | s = socket.socket() 35 | s.connect((ip, int(port))) 36 | 37 | file_size = os.path.getsize(filename) 38 | send_size = 0 39 | 40 | with open(filename, 'rb') as f: 41 | while True: 42 | data = f.read(1024) 43 | if data: 44 | send_size += sys.getsizeof(data) 45 | print 'send %d Bytes' % (send_size) 46 | s.send(data) 47 | else: 48 | break 49 | sleep(0.01) 50 | 51 | s.close() 52 | 53 | if __name__ == '__main__': 54 | if sys.argv[1] == 'server': 55 | server(sys.argv[2], sys.argv[3]) 56 | elif sys.argv[1] == 'client': 57 | client(sys.argv[2], sys.argv[3], sys.argv[4]) 58 | -------------------------------------------------------------------------------- /18-http_server_2/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -g -Wall -Iinclude 3 | LIBS = -lpthread -ldl -lrt 4 | 5 | SRCS := $(wildcard $(SRC_DIR)*.c) 6 | OBJS := $(SRCS:.c=.o) 7 | TARGET := http_server 8 | 9 | all : $(TARGET) 10 | 11 | $(TARGET) : $(OBJS) 12 | $(CC) $(CFLAGS) -o $@ $^ $(LIBS) 13 | 14 | $(OBJS) : %.o : %.c 15 | $(CC) $(CFLAGS) -c -o $@ $< 16 | 17 | clean: 18 | rm -rf $(SRC_DIR)*.o $(TARGET) 19 | 20 | .PHONY:clean 21 | -------------------------------------------------------------------------------- /18-http_server_2/create_randfile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dd if=/dev/urandom bs=1MB count=3 | base64 > client-input.dat 4 | -------------------------------------------------------------------------------- /18-http_server_2/http.h: -------------------------------------------------------------------------------- 1 | #ifndef __HTTP_H__ 2 | #define __HTTP_H__ 3 | 4 | #define HTTP_STR "HTTP" 5 | #define HTTPV0_STR "HTTP/1.0" 6 | #define HTTPV1_STR "HTTP/1.1" 7 | #define HTTP_GET "GET" 8 | #define HTTP_POST "POST" 9 | #define HTTP_CLOSE "Close" 10 | #define HTTP_KEEP_ALIVE "Keep-Alive" 11 | #define HOST_HDR "\nHost:" 12 | #define CONTENT_LENGTH_HDR "\nContent-Length:" 13 | #define CONTENT_TYPE_HDR "\nContent-Type:" 14 | #define CACHE_CONTROL_HDR "\nCache-Control:" 15 | #define CONNECTION_HDR "\nConnection:" 16 | #define DATE_HDR "\nDate:" 17 | #define EXPIRES_HDR "\nExpires:" 18 | #define AGE_HDR "\nAge:" 19 | #define LAST_MODIFIED_HDR "\nLast-Modified:" 20 | #define IF_MODIFIED_SINCE_HDR "\nIf-Modified_Since:" 21 | #define PRAGMA_HDR "\nPragma:" 22 | #define RANGE_HDR "\nRange:" 23 | #define IF_RANGE_HDR "\nIf-Range:" 24 | #define ETAG_HDR "\nETag:" 25 | 26 | enum { GET = 1, POST = 2 }; 27 | 28 | int find_http_header(char *data, int len); 29 | 30 | char* http_header_str_val(const char* buf, const char *key, const int key_len, char* value, int value_len); 31 | 32 | char* http_get_url(char * data, int data_len, char* value, int value_len); 33 | 34 | enum { HTTP_09, HTTP_10, HTTP_11 }; /* http version */ 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /18-http_server_2/include/arp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARP_H__ 2 | #define __ARP_H__ 3 | 4 | #include "base.h" 5 | #include "ether.h" 6 | #include "types.h" 7 | 8 | #define ARPHRD_ETHER 1 9 | 10 | #define ARPOP_REQUEST 1 11 | #define ARPOP_REPLY 2 12 | 13 | struct ether_arp { 14 | u16 arp_hrd; // format of hardware address, should be 0x01 15 | u16 arp_pro; // format of protocol address, should be 0x0800 16 | u8 arp_hln; // length of hardware address, should be 6 17 | u8 arp_pln; // length of protocol address, should be 4 18 | u16 arp_op; // ARP opcode (command) 19 | u8 arp_sha[ETH_ALEN]; // sender hardware address 20 | u32 arp_spa; // sender protocol address 21 | u8 arp_tha[ETH_ALEN]; // target hardware address 22 | u32 arp_tpa; // target protocol address 23 | } __attribute__ ((packed)); 24 | 25 | // get the arp header of the packet 26 | static inline struct ether_arp *packet_to_ether_arp(const char *packet) 27 | { 28 | return (struct ether_arp *)(packet + ETHER_HDR_SIZE); 29 | } 30 | 31 | void handle_arp_packet(iface_info_t *info, char *packet, int len); 32 | void arp_send_request(iface_info_t *iface, u32 dst_ip); 33 | void iface_send_packet_by_arp(iface_info_t *iface, u32 dst_ip, char *packet, int len); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /18-http_server_2/include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE_H__ 2 | #define __BASE_H__ 3 | 4 | #include "types.h" 5 | #include "ether.h" 6 | #include "list.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | typedef struct { 28 | struct list_head iface_list; // the list of interfaces 29 | int nifs; // number of interfaces 30 | struct pollfd *fds; // structure used to poll packets among 31 | // all the interfaces 32 | } ustack_t; 33 | 34 | extern ustack_t *instance; 35 | 36 | typedef struct { 37 | struct list_head list; // list node used to link all interfaces 38 | 39 | int fd; // file descriptor for receiving & sending packets 40 | int index; // the index (unique ID) of this interface 41 | u8 mac[ETH_ALEN]; // mac address of this interface 42 | u32 ip; // IPv4 address (in host byte order) 43 | u32 mask; // Network Mask (in host byte order) 44 | char name[16]; // name of this interface 45 | char ip_str[16]; // readable IP address 46 | } iface_info_t; 47 | 48 | void init_ustack(); 49 | iface_info_t *fd_to_iface(int fd); 50 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 51 | #endif 52 | -------------------------------------------------------------------------------- /18-http_server_2/include/checksum.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHECKSUM_H__ 2 | #define __CHECKSUM_H__ 3 | 4 | #include "types.h" 5 | 6 | // calculate the checksum of the given buf, providing sum 7 | // as the initial value 8 | static inline u16 checksum(void *t_buf, int nbytes, u32 sum) 9 | { 10 | u16 * buf = t_buf; 11 | for (int i = 0; i < nbytes / 2; i++) 12 | sum += buf[i]; 13 | 14 | if (nbytes % 2) 15 | sum += ((u8 *)buf)[nbytes-1]; 16 | 17 | while (sum >> 16) 18 | sum = (sum >> 16) + (sum & 0xffff); 19 | 20 | return (u16)~sum; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /18-http_server_2/include/ether.h: -------------------------------------------------------------------------------- 1 | #ifndef __ETHER_H__ 2 | #define __ETHER_H__ 3 | 4 | #include "types.h" 5 | 6 | #define ETH_ALEN 6 // length of mac address 7 | #define ETH_FRAME_LEN 1514 // maximum length of an ethernet frame (packet) 8 | 9 | // protocol format in ethernet header 10 | #define ETH_P_ALL 0x0003 // every packet, only used when tending to receive all packets 11 | #define ETH_P_IP 0x0800 // IP packet 12 | #define ETH_P_ARP 0x0806 // ARP packet 13 | 14 | struct ether_header { 15 | u8 ether_dhost[ETH_ALEN]; // destination mac address 16 | u8 ether_shost[ETH_ALEN]; // source mac address 17 | u16 ether_type; // protocol format 18 | }; 19 | 20 | #define ETHER_HDR_SIZE sizeof(struct ether_header) 21 | 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /18-http_server_2/include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __HASH_H__ 2 | #define __HASH_H__ 3 | 4 | #include "types.h" 5 | 6 | #define HASH_8BITS 256 7 | #define HASH_16BITS 65536 8 | 9 | // the simplest hash functions, you can recreate the wheels as you wish 10 | 11 | static inline u8 hash8(char *buf, int len) 12 | { 13 | u8 result = 0; 14 | for (int i = 0; i < len; i++) 15 | result ^= buf[i]; 16 | 17 | return result; 18 | } 19 | 20 | static inline u16 hash16(char *buf, int len) 21 | { 22 | u16 result = 0; 23 | for (int i = 0; i < len / 2 * 2; i += 2) 24 | result ^= *(u16 *)(buf + i); 25 | 26 | if (len % 2) 27 | result ^= (u8)(buf[len-1]); 28 | 29 | return result; 30 | } 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /18-http_server_2/include/icmp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ICMP_H__ 2 | #define __ICMP_H__ 3 | 4 | #include "types.h" 5 | #include "checksum.h" 6 | #include "base.h" 7 | 8 | struct icmphdr { 9 | u8 type; // type of icmp message 10 | u8 code; // icmp code 11 | u16 checksum; 12 | u16 icmp_identifier; // icmp identifier, used in icmp echo request 13 | u16 icmp_sequence; // icmp sequence, used in icmp echo request 14 | }__attribute__((packed)); 15 | 16 | #define ICMP_HDR_SIZE sizeof(struct icmphdr) 17 | #define ICMP_COPIED_DATA_LEN 8 18 | 19 | #define ICMP_ECHOREQUEST 8 // echo request 20 | #define ICMP_ECHOREPLY 0 // echo reply 21 | #define ICMP_DEST_UNREACH 3 // destination unreachable 22 | #define ICMP_TIME_EXCEEDED 11 // time exceeded 23 | 24 | // codes for UNREACH 25 | #define ICMP_NET_UNREACH 0 // network unreachable 26 | #define ICMP_HOST_UNREACH 1 // host unreachable 27 | 28 | // code for TIME_EXCEEDED 29 | #define ICMP_EXC_TTL 0 // ttl count exceeded 30 | 31 | // calculate the checksum of icmp data, note that the length of icmp data varies 32 | static inline u16 icmp_checksum(struct icmphdr *icmp, int len) 33 | { 34 | u16 tmp = icmp->checksum; 35 | icmp->checksum = 0; 36 | u16 sum = checksum((u16 *)icmp, len, 0); 37 | icmp->checksum = tmp; 38 | 39 | return sum; 40 | } 41 | 42 | // construct icmp packet according to type, code and incoming packet, and send it 43 | void icmp_send_packet(const char *in_pkt, int len, u8 type, u8 code); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /18-http_server_2/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // #define LOG_DEBUG 9 | 10 | enum log_level { DEBUG = 0, INFO, WARNING, ERROR }; 11 | 12 | static enum log_level this_log_level = DEBUG; 13 | 14 | static const char *log_level_str[] = { "DEBUG", "INFO", "WARNING", "ERROR" }; 15 | 16 | #ifdef LOG_DEBUG 17 | #define log_it(fmt, level_str, ...) \ 18 | fprintf(stderr, "[%s:%u] %s: " fmt "\n", __FILE__, __LINE__, \ 19 | level_str, ##__VA_ARGS__); 20 | #else 21 | #define log_it(fmt, level_str, ...) \ 22 | fprintf(stderr, "%s: " fmt "\n", level_str, ##__VA_ARGS__); 23 | #endif 24 | 25 | #define log(level, fmt, ...) \ 26 | do { \ 27 | if (level < this_log_level) \ 28 | break; \ 29 | log_it(fmt, log_level_str[level], ##__VA_ARGS__); \ 30 | } while (0) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /18-http_server_2/include/packet.h: -------------------------------------------------------------------------------- 1 | #ifndef __PACKET_H__ 2 | #define __PACKET_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 8 | void broadcast_packet(iface_info_t *iface, char *packet, int len); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /18-http_server_2/include/rtable.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTABLE_H__ 2 | #define __RTABLE_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | #include "list.h" 8 | 9 | // structure of ip forwarding table 10 | // note: 1, the table supports only ipv4 address; 11 | // 2, addresses are stored in host byte order. 12 | typedef struct { 13 | struct list_head list; 14 | u32 dest; // destination ip address (could be network or host) 15 | u32 mask; // network mask of dest 16 | u32 gw; // ip address of next hop (will be 0 if dest is in 17 | // the same network with iface) 18 | int flags; // flags (could be omitted here) 19 | char if_name[16]; // name of the interface 20 | iface_info_t *iface; // pointer to the interface structure 21 | } rt_entry_t; 22 | 23 | extern struct list_head rtable; 24 | 25 | void init_rtable(); 26 | void load_static_rtable(); 27 | void clear_rtable(); 28 | void add_rt_entry(rt_entry_t *entry); 29 | void remove_rt_entry(rt_entry_t *entry); 30 | void print_rtable(); 31 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface); 32 | 33 | rt_entry_t *longest_prefix_match(u32 ip); 34 | u32 get_next_hop(rt_entry_t *entry, u32 dst); 35 | 36 | void load_rtable_from_kernel(); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /18-http_server_2/include/tcp_apps.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_APPS_H__ 2 | #define __TCP_APPS_H__ 3 | 4 | extern char filename[100]; 5 | 6 | void *http_server(void *arg); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /18-http_server_2/include/tcp_hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_HASH_H__ 2 | #define __TCP_HASH_H__ 3 | 4 | #include "hash.h" 5 | #include "list.h" 6 | #include "tcp_sock.h" 7 | 8 | #define TCP_HASH_SIZE HASH_8BITS 9 | #define TCP_HASH_MASK (TCP_HASH_SIZE - 1) 10 | 11 | // the 3 tables in tcp_hash_table 12 | struct tcp_hash_table { 13 | struct list_head established_table[TCP_HASH_SIZE]; 14 | struct list_head listen_table[TCP_HASH_SIZE]; 15 | struct list_head bind_table[TCP_HASH_SIZE]; 16 | }; 17 | 18 | // tcp hash function: if hashed into bind_table or listen_table, only use sport; 19 | // otherwise, use all the 4 arguments 20 | static inline int tcp_hash_function(u32 saddr, u32 daddr, u16 sport, u16 dport) 21 | { 22 | int result = hash8((char *)&saddr, 4) ^ hash8((char *)&daddr, 4) ^ \ 23 | hash8((char *)&sport, 2) ^ hash8((char *)&dport, 2); 24 | 25 | return result & TCP_HASH_MASK; 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /18-http_server_2/include/tcp_timer.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_TIMER_H__ 2 | #define __TCP_TIMER_H__ 3 | 4 | #include "list.h" 5 | 6 | #include 7 | 8 | struct tcp_timer { 9 | int type; // time-wait: 0 retrans: 1 10 | #define TIMER_TYPE_TIME_WAIT 0 11 | #define TIMER_TYPE_RETRANS 1 12 | 13 | int timeout; // in micro second 14 | struct list_head list; 15 | int enable; 16 | }; 17 | 18 | struct tcp_sock; 19 | #define timewait_to_tcp_sock(t) \ 20 | (struct tcp_sock *)((char *)(t) - offsetof(struct tcp_sock, timewait)) 21 | 22 | #define retranstimer_to_tcp_sock(t) \ 23 | (struct tcp_sock *)((char *)(t) - offsetof(struct tcp_sock, retrans_timer)) 24 | #define TCP_TIMER_SCAN_INTERVAL 100000 25 | #define TCP_MSL 1000000 26 | #define TCP_TIMEWAIT_TIMEOUT (2 * TCP_MSL) 27 | #define TCP_RETRANS_INTERVAL_INITIAL 200000 28 | 29 | // the thread that scans timer_list periodically 30 | void *tcp_timer_thread(void *arg); 31 | // add the timer of tcp sock to timer_list 32 | void tcp_set_timewait_timer(struct tcp_sock *); 33 | 34 | void tcp_set_retrans_timer(struct tcp_sock *tsk); 35 | 36 | void tcp_unset_retrans_timer(struct tcp_sock *tsk); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /18-http_server_2/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | 6 | typedef uint8_t u8; 7 | typedef uint16_t u16; 8 | typedef uint32_t u32; 9 | typedef uint64_t u64; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /18-http_server_2/ip.c: -------------------------------------------------------------------------------- 1 | #include "ip.h" 2 | #include "icmp.h" 3 | #include "arpcache.h" 4 | #include "rtable.h" 5 | #include "arp.h" 6 | #include "tcp.h" 7 | 8 | #include "log.h" 9 | 10 | #include 11 | 12 | 13 | void handle_ip_packet(iface_info_t *iface, char *packet, int len) 14 | { 15 | struct iphdr *ip = packet_to_ip_hdr(packet); 16 | u32 daddr = ntohl(ip->daddr); 17 | if (daddr == iface->ip) { 18 | if (ip->protocol == IPPROTO_ICMP) { 19 | struct icmphdr *icmp = (struct icmphdr *)IP_DATA(ip); 20 | if (icmp->type == ICMP_ECHOREQUEST) { 21 | icmp_send_packet(packet, len, ICMP_ECHOREPLY, 0); 22 | } 23 | } 24 | else if (ip->protocol == IPPROTO_TCP) { 25 | handle_tcp_packet(packet, ip, (struct tcphdr *)(IP_DATA(ip))); 26 | } 27 | else { 28 | log(ERROR, "unsupported IP protocol (0x%x) packet.", ip->protocol); 29 | } 30 | 31 | free(packet); 32 | } 33 | else { 34 | // ip_forward_packet(daddr, packet, len); 35 | log(ERROR, "received packet with incorrect destination IP address."); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /18-http_server_2/rtable.c: -------------------------------------------------------------------------------- 1 | #include "rtable.h" 2 | #include "ip.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct list_head rtable; 9 | 10 | void init_rtable() 11 | { 12 | init_list_head(&rtable); 13 | } 14 | 15 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface) 16 | { 17 | rt_entry_t *entry = malloc(sizeof(*entry)); 18 | memset(entry, 0, sizeof(*entry)); 19 | 20 | init_list_head(&(entry->list)); 21 | entry->dest = dest; 22 | entry->mask = mask; 23 | entry->gw = gw; 24 | entry->iface = iface; 25 | strcpy(entry->if_name, iface->name); 26 | 27 | return entry; 28 | } 29 | 30 | void add_rt_entry(rt_entry_t *entry) 31 | { 32 | list_add_tail(&entry->list, &rtable); 33 | } 34 | 35 | void remove_rt_entry(rt_entry_t *entry) 36 | { 37 | list_delete_entry(&entry->list); 38 | free(entry); 39 | } 40 | 41 | void clear_rtable() 42 | { 43 | struct list_head *head = &rtable, *tmp; 44 | while (head->next != head) { 45 | tmp = head->next; 46 | list_delete_entry(tmp); 47 | rt_entry_t *entry = list_entry(tmp, rt_entry_t, list); 48 | free(entry); 49 | } 50 | } 51 | 52 | void print_rtable() 53 | { 54 | // Print the routing table 55 | fprintf(stdout, "Routing Table:\n"); 56 | fprintf(stdout, "dest\tmask\tgateway\tif_name\n"); 57 | fprintf(stdout, "--------------------------------------\n"); 58 | rt_entry_t *entry = NULL; 59 | list_for_each_entry(entry, &rtable, list) { 60 | fprintf(stdout, IP_FMT"\t"IP_FMT"\t"IP_FMT"\t%s\n", \ 61 | HOST_IP_FMT_STR(entry->dest), \ 62 | HOST_IP_FMT_STR(entry->mask), \ 63 | HOST_IP_FMT_STR(entry->gw), \ 64 | entry->if_name); 65 | } 66 | fprintf(stdout, "--------------------------------------\n"); 67 | } 68 | -------------------------------------------------------------------------------- /18-http_server_2/scripts/disable_arp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | arptables -A FORWARD -j DROP 4 | arptables -A OUTPUT -j DROP 5 | -------------------------------------------------------------------------------- /18-http_server_2/scripts/disable_icmp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p icmp --icmp-type echo-request -j DROP 4 | iptables -A OUTPUT -p icmp --icmp-type echo-reply -j DROP 5 | iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP 6 | -------------------------------------------------------------------------------- /18-http_server_2/scripts/disable_ip_forward.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p ip -j DROP 4 | echo 0 > /proc/sys/net/ipv4/ip_forward 5 | -------------------------------------------------------------------------------- /18-http_server_2/scripts/disable_ipv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w net.ipv6.conf.all.disable_ipv6=1 4 | sysctl -w net.ipv6.conf.default.disable_ipv6=1 5 | -------------------------------------------------------------------------------- /18-http_server_2/scripts/disable_offloading.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The virtual NIC does not support "lro rxhash" options. 4 | TOE_OPTIONS="rx tx sg tso ufo gso gro rxvlan txvlan" 5 | 6 | for IFACE in `/sbin/ifconfig | grep '^.*-eth[0-9]' | awk '{print $1}'`; do 7 | echo "Disabling $IFACE ..." 8 | for TOE_OPTION in $TOE_OPTIONS; do 9 | /sbin/ethtool --offload "$IFACE" "$TOE_OPTION" off 10 | done 11 | done 12 | -------------------------------------------------------------------------------- /18-http_server_2/scripts/disable_tcp_rst.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP 4 | -------------------------------------------------------------------------------- /18-http_server_2/tcp_apps.c: -------------------------------------------------------------------------------- 1 | #include "tcp_sock.h" 2 | 3 | // #include "log.h" 4 | 5 | #include 6 | #include 7 | 8 | char filename[100]; 9 | 10 | // tcp server application, listens to port (specified by arg) and serves only one 11 | // connection request 12 | 13 | -------------------------------------------------------------------------------- /18-http_server_2/tcp_stack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import sys 4 | import string 5 | import socket 6 | from time import sleep 7 | 8 | data = string.digits + string.lowercase + string.uppercase 9 | 10 | def server(port): 11 | s = socket.socket() 12 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 13 | 14 | s.bind(('0.0.0.0', int(port))) 15 | s.listen(3) 16 | 17 | cs, addr = s.accept() 18 | print addr 19 | 20 | while True: 21 | data = cs.recv(1000) 22 | print(type(data)) 23 | if data: 24 | data = 'server echoes: ' + data 25 | cs.send(data) 26 | else: 27 | break 28 | 29 | s.close() 30 | 31 | 32 | def client(ip, port): 33 | s = socket.socket() 34 | s.connect((ip, int(port))) 35 | 36 | for i in range(10): 37 | new_data = data[i:] + data[:i+1] 38 | s.send(new_data) 39 | print s.recv(1000) 40 | sleep(1) 41 | 42 | s.close() 43 | 44 | if __name__ == '__main__': 45 | if sys.argv[1] == 'server': 46 | server(sys.argv[2]) 47 | elif sys.argv[1] == 'client': 48 | client(sys.argv[2], sys.argv[3]) 49 | -------------------------------------------------------------------------------- /18-http_server_2/tcp_stack_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import os 4 | import sys 5 | import string 6 | import socket 7 | import struct 8 | from time import sleep 9 | 10 | data = string.digits + string.lowercase + string.uppercase 11 | 12 | def server(port, filename): 13 | s = socket.socket() 14 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 15 | 16 | s.bind(('0.0.0.0', int(port))) 17 | s.listen(3) 18 | 19 | cs, addr = s.accept() 20 | print addr 21 | 22 | with open(filename, 'wb') as f: 23 | while True: 24 | data = cs.recv(1024) 25 | if data: 26 | f.write(data) 27 | else: 28 | break 29 | 30 | s.close() 31 | 32 | 33 | def client(ip, port, filename): 34 | s = socket.socket() 35 | s.connect((ip, int(port))) 36 | 37 | file_size = os.path.getsize(filename) 38 | send_size = 0 39 | 40 | with open(filename, 'rb') as f: 41 | while True: 42 | data = f.read(1024) 43 | if data: 44 | send_size += sys.getsizeof(data) 45 | print 'send %d Bytes' % (send_size) 46 | s.send(data) 47 | else: 48 | break 49 | sleep(0.01) 50 | 51 | s.close() 52 | 53 | if __name__ == '__main__': 54 | if sys.argv[1] == 'server': 55 | server(sys.argv[2], sys.argv[3]) 56 | elif sys.argv[1] == 'client': 57 | client(sys.argv[2], sys.argv[3], sys.argv[4]) 58 | -------------------------------------------------------------------------------- /18-http_server_4/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = tcp_stack 2 | all: $(TARGET) 3 | 4 | CC = gcc 5 | LD = gcc 6 | 7 | CFLAGS = -g -Wall -Iinclude 8 | LDFLAGS = 9 | 10 | LIBS = -lpthread 11 | 12 | HDRS = ./include/*.h 13 | 14 | SRCS = arp.c arpcache.c device_internal.c icmp.c ip_base.c ip.c main.c rtable.c rtable_internal.c \ 15 | tcp.c http-client.c http-server.c tcp_in.c tcp_out.c tcp_sock.c tcp_timer.c 16 | 17 | OBJS = $(patsubst %.c,%.o,$(SRCS)) 18 | 19 | $(OBJS) : %.o : %.c include/*.h 20 | $(CC) -c $(CFLAGS) $< -o $@ 21 | 22 | $(TARGET): $(OBJS) 23 | $(LD) $(LDFLAGS) $(OBJS) -o $(TARGET) $(LIBS) 24 | 25 | clean: 26 | rm -f *.o $(TARGET) 27 | -------------------------------------------------------------------------------- /18-http_server_4/create_randfile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dd if=/dev/urandom bs=1MB count=3 | base64 > client-input.dat 4 | -------------------------------------------------------------------------------- /18-http_server_4/include/arp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ARP_H__ 2 | #define __ARP_H__ 3 | 4 | #include "base.h" 5 | #include "ether.h" 6 | #include "types.h" 7 | 8 | #define ARPHRD_ETHER 1 9 | 10 | #define ARPOP_REQUEST 1 11 | #define ARPOP_REPLY 2 12 | 13 | struct ether_arp { 14 | u16 arp_hrd; // format of hardware address, should be 0x01 15 | u16 arp_pro; // format of protocol address, should be 0x0800 16 | u8 arp_hln; // length of hardware address, should be 6 17 | u8 arp_pln; // length of protocol address, should be 4 18 | u16 arp_op; // ARP opcode (command) 19 | u8 arp_sha[ETH_ALEN]; // sender hardware address 20 | u32 arp_spa; // sender protocol address 21 | u8 arp_tha[ETH_ALEN]; // target hardware address 22 | u32 arp_tpa; // target protocol address 23 | } __attribute__ ((packed)); 24 | 25 | // get the arp header of the packet 26 | static inline struct ether_arp *packet_to_ether_arp(const char *packet) 27 | { 28 | return (struct ether_arp *)(packet + ETHER_HDR_SIZE); 29 | } 30 | 31 | void handle_arp_packet(iface_info_t *info, char *packet, int len); 32 | void arp_send_request(iface_info_t *iface, u32 dst_ip); 33 | void iface_send_packet_by_arp(iface_info_t *iface, u32 dst_ip, char *packet, int len); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /18-http_server_4/include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef __BASE_H__ 2 | #define __BASE_H__ 3 | 4 | #include "types.h" 5 | #include "ether.h" 6 | #include "list.h" 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | typedef struct { 28 | struct list_head iface_list; // the list of interfaces 29 | int nifs; // number of interfaces 30 | struct pollfd *fds; // structure used to poll packets among 31 | // all the interfaces 32 | } ustack_t; 33 | 34 | extern ustack_t *instance; 35 | 36 | typedef struct { 37 | struct list_head list; // list node used to link all interfaces 38 | 39 | int fd; // file descriptor for receiving & sending packets 40 | int index; // the index (unique ID) of this interface 41 | u8 mac[ETH_ALEN]; // mac address of this interface 42 | u32 ip; // IPv4 address (in host byte order) 43 | u32 mask; // Network Mask (in host byte order) 44 | char name[16]; // name of this interface 45 | char ip_str[16]; // readable IP address 46 | } iface_info_t; 47 | 48 | void init_ustack(); 49 | iface_info_t *fd_to_iface(int fd); 50 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 51 | #endif 52 | -------------------------------------------------------------------------------- /18-http_server_4/include/checksum.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHECKSUM_H__ 2 | #define __CHECKSUM_H__ 3 | 4 | #include "types.h" 5 | 6 | // calculate the checksum of the given buf, providing sum 7 | // as the initial value 8 | static inline u16 checksum(void *t_buf, int nbytes, u32 sum) 9 | { 10 | u16 * buf = t_buf; 11 | for (int i = 0; i < nbytes / 2; i++) 12 | sum += buf[i]; 13 | 14 | if (nbytes % 2) 15 | sum += ((u8 *)buf)[nbytes-1]; 16 | 17 | while (sum >> 16) 18 | sum = (sum >> 16) + (sum & 0xffff); 19 | 20 | return (u16)~sum; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /18-http_server_4/include/ether.h: -------------------------------------------------------------------------------- 1 | #ifndef __ETHER_H__ 2 | #define __ETHER_H__ 3 | 4 | #include "types.h" 5 | 6 | #define ETH_ALEN 6 // length of mac address 7 | #define ETH_FRAME_LEN 1514 // maximum length of an ethernet frame (packet) 8 | 9 | // protocol format in ethernet header 10 | #define ETH_P_ALL 0x0003 // every packet, only used when tending to receive all packets 11 | #define ETH_P_IP 0x0800 // IP packet 12 | #define ETH_P_ARP 0x0806 // ARP packet 13 | 14 | struct ether_header { 15 | u8 ether_dhost[ETH_ALEN]; // destination mac address 16 | u8 ether_shost[ETH_ALEN]; // source mac address 17 | u16 ether_type; // protocol format 18 | }; 19 | 20 | #define ETHER_HDR_SIZE sizeof(struct ether_header) 21 | 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /18-http_server_4/include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __HASH_H__ 2 | #define __HASH_H__ 3 | 4 | #include "types.h" 5 | 6 | #define HASH_8BITS 256 7 | #define HASH_16BITS 65536 8 | 9 | // the simplest hash functions, you can recreate the wheels as you wish 10 | 11 | static inline u8 hash8(char *buf, int len) 12 | { 13 | u8 result = 0; 14 | for (int i = 0; i < len; i++) 15 | result ^= buf[i]; 16 | 17 | return result; 18 | } 19 | 20 | static inline u16 hash16(char *buf, int len) 21 | { 22 | u16 result = 0; 23 | for (int i = 0; i < len / 2 * 2; i += 2) 24 | result ^= *(u16 *)(buf + i); 25 | 26 | if (len % 2) 27 | result ^= (u8)(buf[len-1]); 28 | 29 | return result; 30 | } 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /18-http_server_4/include/icmp.h: -------------------------------------------------------------------------------- 1 | #ifndef __ICMP_H__ 2 | #define __ICMP_H__ 3 | 4 | #include "types.h" 5 | #include "checksum.h" 6 | #include "base.h" 7 | 8 | struct icmphdr { 9 | u8 type; // type of icmp message 10 | u8 code; // icmp code 11 | u16 checksum; 12 | u16 icmp_identifier; // icmp identifier, used in icmp echo request 13 | u16 icmp_sequence; // icmp sequence, used in icmp echo request 14 | }__attribute__((packed)); 15 | 16 | #define ICMP_HDR_SIZE sizeof(struct icmphdr) 17 | #define ICMP_COPIED_DATA_LEN 8 18 | 19 | #define ICMP_ECHOREQUEST 8 // echo request 20 | #define ICMP_ECHOREPLY 0 // echo reply 21 | #define ICMP_DEST_UNREACH 3 // destination unreachable 22 | #define ICMP_TIME_EXCEEDED 11 // time exceeded 23 | 24 | // codes for UNREACH 25 | #define ICMP_NET_UNREACH 0 // network unreachable 26 | #define ICMP_HOST_UNREACH 1 // host unreachable 27 | 28 | // code for TIME_EXCEEDED 29 | #define ICMP_EXC_TTL 0 // ttl count exceeded 30 | 31 | // calculate the checksum of icmp data, note that the length of icmp data varies 32 | static inline u16 icmp_checksum(struct icmphdr *icmp, int len) 33 | { 34 | u16 tmp = icmp->checksum; 35 | icmp->checksum = 0; 36 | u16 sum = checksum((u16 *)icmp, len, 0); 37 | icmp->checksum = tmp; 38 | 39 | return sum; 40 | } 41 | 42 | // construct icmp packet according to type, code and incoming packet, and send it 43 | void icmp_send_packet(const char *in_pkt, int len, u8 type, u8 code); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /18-http_server_4/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOG_H__ 2 | #define __LOG_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // #define LOG_DEBUG 9 | 10 | enum log_level { DEBUG = 0, INFO, WARNING, ERROR }; 11 | 12 | static enum log_level this_log_level = DEBUG; 13 | 14 | static const char *log_level_str[] = { "DEBUG", "INFO", "WARNING", "ERROR" }; 15 | 16 | #ifdef LOG_DEBUG 17 | #define log_it(fmt, level_str, ...) \ 18 | fprintf(stderr, "[%s:%u] %s: " fmt "\n", __FILE__, __LINE__, \ 19 | level_str, ##__VA_ARGS__); 20 | #else 21 | #define log_it(fmt, level_str, ...) \ 22 | fprintf(stderr, "%s: " fmt "\n", level_str, ##__VA_ARGS__); 23 | #endif 24 | 25 | #define log(level, fmt, ...) \ 26 | do { \ 27 | if (level < this_log_level) \ 28 | break; \ 29 | log_it(fmt, log_level_str[level], ##__VA_ARGS__); \ 30 | } while (0) 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /18-http_server_4/include/packet.h: -------------------------------------------------------------------------------- 1 | #ifndef __PACKET_H__ 2 | #define __PACKET_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | void iface_send_packet(iface_info_t *iface, char *packet, int len); 8 | void broadcast_packet(iface_info_t *iface, char *packet, int len); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /18-http_server_4/include/rtable.h: -------------------------------------------------------------------------------- 1 | #ifndef __RTABLE_H__ 2 | #define __RTABLE_H__ 3 | 4 | #include "base.h" 5 | #include "types.h" 6 | 7 | #include "list.h" 8 | 9 | // structure of ip forwarding table 10 | // note: 1, the table supports only ipv4 address; 11 | // 2, addresses are stored in host byte order. 12 | typedef struct { 13 | struct list_head list; 14 | u32 dest; // destination ip address (could be network or host) 15 | u32 mask; // network mask of dest 16 | u32 gw; // ip address of next hop (will be 0 if dest is in 17 | // the same network with iface) 18 | int flags; // flags (could be omitted here) 19 | char if_name[16]; // name of the interface 20 | iface_info_t *iface; // pointer to the interface structure 21 | } rt_entry_t; 22 | 23 | extern struct list_head rtable; 24 | 25 | void init_rtable(); 26 | void load_static_rtable(); 27 | void clear_rtable(); 28 | void add_rt_entry(rt_entry_t *entry); 29 | void remove_rt_entry(rt_entry_t *entry); 30 | void print_rtable(); 31 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface); 32 | 33 | rt_entry_t *longest_prefix_match(u32 ip); 34 | u32 get_next_hop(rt_entry_t *entry, u32 dst); 35 | 36 | void load_rtable_from_kernel(); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /18-http_server_4/include/tcp_apps.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_APPS_H__ 2 | #define __TCP_APPS_H__ 3 | 4 | extern char filename[100]; 5 | 6 | void *http_server(void *arg); 7 | void *http_client(void *arg); 8 | 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /18-http_server_4/include/tcp_hash.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_HASH_H__ 2 | #define __TCP_HASH_H__ 3 | 4 | #include "hash.h" 5 | #include "list.h" 6 | #include "tcp_sock.h" 7 | 8 | #define TCP_HASH_SIZE HASH_8BITS 9 | #define TCP_HASH_MASK (TCP_HASH_SIZE - 1) 10 | 11 | // the 3 tables in tcp_hash_table 12 | struct tcp_hash_table { 13 | struct list_head established_table[TCP_HASH_SIZE]; 14 | struct list_head listen_table[TCP_HASH_SIZE]; 15 | struct list_head bind_table[TCP_HASH_SIZE]; 16 | }; 17 | 18 | // tcp hash function: if hashed into bind_table or listen_table, only use sport; 19 | // otherwise, use all the 4 arguments 20 | static inline int tcp_hash_function(u32 saddr, u32 daddr, u16 sport, u16 dport) 21 | { 22 | int result = hash8((char *)&saddr, 4) ^ hash8((char *)&daddr, 4) ^ \ 23 | hash8((char *)&sport, 2) ^ hash8((char *)&dport, 2); 24 | 25 | return result & TCP_HASH_MASK; 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /18-http_server_4/include/tcp_timer.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_TIMER_H__ 2 | #define __TCP_TIMER_H__ 3 | 4 | #include "list.h" 5 | 6 | #include 7 | 8 | struct tcp_timer { 9 | int type; // time-wait: 0 retrans: 1 10 | #define TIMER_TYPE_TIME_WAIT 0 11 | #define TIMER_TYPE_RETRANS 1 12 | 13 | int timeout; // in micro second 14 | struct list_head list; 15 | int enable; 16 | }; 17 | 18 | struct tcp_sock; 19 | #define timewait_to_tcp_sock(t) \ 20 | (struct tcp_sock *)((char *)(t) - offsetof(struct tcp_sock, timewait)) 21 | 22 | #define retranstimer_to_tcp_sock(t) \ 23 | (struct tcp_sock *)((char *)(t) - offsetof(struct tcp_sock, retrans_timer)) 24 | #define TCP_TIMER_SCAN_INTERVAL 100000 25 | #define TCP_MSL 1000000 26 | #define TCP_TIMEWAIT_TIMEOUT (2 * TCP_MSL) 27 | #define TCP_RETRANS_INTERVAL_INITIAL 200000 28 | 29 | // the thread that scans timer_list periodically 30 | void *tcp_timer_thread(void *arg); 31 | // add the timer of tcp sock to timer_list 32 | void tcp_set_timewait_timer(struct tcp_sock *); 33 | 34 | void tcp_set_retrans_timer(struct tcp_sock *tsk); 35 | 36 | void tcp_unset_retrans_timer(struct tcp_sock *tsk); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /18-http_server_4/include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | 6 | typedef uint8_t u8; 7 | typedef uint16_t u16; 8 | typedef uint32_t u32; 9 | typedef uint64_t u64; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /18-http_server_4/ip.c: -------------------------------------------------------------------------------- 1 | #include "ip.h" 2 | #include "icmp.h" 3 | #include "arpcache.h" 4 | #include "rtable.h" 5 | #include "arp.h" 6 | #include "tcp.h" 7 | 8 | #include "log.h" 9 | 10 | #include 11 | 12 | 13 | void handle_ip_packet(iface_info_t *iface, char *packet, int len) 14 | { 15 | struct iphdr *ip = packet_to_ip_hdr(packet); 16 | u32 daddr = ntohl(ip->daddr); 17 | if (daddr == iface->ip) { 18 | if (ip->protocol == IPPROTO_ICMP) { 19 | struct icmphdr *icmp = (struct icmphdr *)IP_DATA(ip); 20 | if (icmp->type == ICMP_ECHOREQUEST) { 21 | icmp_send_packet(packet, len, ICMP_ECHOREPLY, 0); 22 | } 23 | } 24 | else if (ip->protocol == IPPROTO_TCP) { 25 | handle_tcp_packet(packet, ip, (struct tcphdr *)(IP_DATA(ip))); 26 | } 27 | else { 28 | log(ERROR, "unsupported IP protocol (0x%x) packet.", ip->protocol); 29 | } 30 | 31 | free(packet); 32 | } 33 | else { 34 | // ip_forward_packet(daddr, packet, len); 35 | log(ERROR, "received packet with incorrect destination IP address."); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /18-http_server_4/rtable.c: -------------------------------------------------------------------------------- 1 | #include "rtable.h" 2 | #include "ip.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct list_head rtable; 9 | 10 | void init_rtable() 11 | { 12 | init_list_head(&rtable); 13 | } 14 | 15 | rt_entry_t *new_rt_entry(u32 dest, u32 mask, u32 gw, iface_info_t *iface) 16 | { 17 | rt_entry_t *entry = malloc(sizeof(*entry)); 18 | memset(entry, 0, sizeof(*entry)); 19 | 20 | init_list_head(&(entry->list)); 21 | entry->dest = dest; 22 | entry->mask = mask; 23 | entry->gw = gw; 24 | entry->iface = iface; 25 | strcpy(entry->if_name, iface->name); 26 | 27 | return entry; 28 | } 29 | 30 | void add_rt_entry(rt_entry_t *entry) 31 | { 32 | list_add_tail(&entry->list, &rtable); 33 | } 34 | 35 | void remove_rt_entry(rt_entry_t *entry) 36 | { 37 | list_delete_entry(&entry->list); 38 | free(entry); 39 | } 40 | 41 | void clear_rtable() 42 | { 43 | struct list_head *head = &rtable, *tmp; 44 | while (head->next != head) { 45 | tmp = head->next; 46 | list_delete_entry(tmp); 47 | rt_entry_t *entry = list_entry(tmp, rt_entry_t, list); 48 | free(entry); 49 | } 50 | } 51 | 52 | void print_rtable() 53 | { 54 | // Print the routing table 55 | fprintf(stdout, "Routing Table:\n"); 56 | fprintf(stdout, "dest\tmask\tgateway\tif_name\n"); 57 | fprintf(stdout, "--------------------------------------\n"); 58 | rt_entry_t *entry = NULL; 59 | list_for_each_entry(entry, &rtable, list) { 60 | fprintf(stdout, IP_FMT"\t"IP_FMT"\t"IP_FMT"\t%s\n", \ 61 | HOST_IP_FMT_STR(entry->dest), \ 62 | HOST_IP_FMT_STR(entry->mask), \ 63 | HOST_IP_FMT_STR(entry->gw), \ 64 | entry->if_name); 65 | } 66 | fprintf(stdout, "--------------------------------------\n"); 67 | } 68 | -------------------------------------------------------------------------------- /18-http_server_4/scripts/disable_arp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | arptables -A FORWARD -j DROP 4 | arptables -A OUTPUT -j DROP 5 | -------------------------------------------------------------------------------- /18-http_server_4/scripts/disable_icmp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p icmp --icmp-type echo-request -j DROP 4 | iptables -A OUTPUT -p icmp --icmp-type echo-reply -j DROP 5 | iptables -I OUTPUT -p icmp --icmp-type destination-unreachable -j DROP 6 | -------------------------------------------------------------------------------- /18-http_server_4/scripts/disable_ip_forward.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A INPUT -p ip -j DROP 4 | echo 0 > /proc/sys/net/ipv4/ip_forward 5 | -------------------------------------------------------------------------------- /18-http_server_4/scripts/disable_ipv6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w net.ipv6.conf.all.disable_ipv6=1 4 | sysctl -w net.ipv6.conf.default.disable_ipv6=1 5 | -------------------------------------------------------------------------------- /18-http_server_4/scripts/disable_offloading.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # The virtual NIC does not support "lro rxhash" options. 4 | TOE_OPTIONS="rx tx sg tso ufo gso gro rxvlan txvlan" 5 | 6 | for IFACE in `/sbin/ifconfig | grep '^.*-eth[0-9]' | awk '{print $1}'`; do 7 | echo "Disabling $IFACE ..." 8 | for TOE_OPTION in $TOE_OPTIONS; do 9 | /sbin/ethtool --offload "$IFACE" "$TOE_OPTION" off 10 | done 11 | done 12 | -------------------------------------------------------------------------------- /18-http_server_4/scripts/disable_tcp_rst.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP 4 | -------------------------------------------------------------------------------- /18-http_server_4/tcp_stack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import sys 4 | import string 5 | import socket 6 | from time import sleep 7 | 8 | data = string.digits + string.lowercase + string.uppercase 9 | 10 | def server(port): 11 | s = socket.socket() 12 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 13 | 14 | s.bind(('0.0.0.0', int(port))) 15 | s.listen(3) 16 | 17 | cs, addr = s.accept() 18 | print addr 19 | 20 | while True: 21 | data = cs.recv(1000) 22 | print(type(data)) 23 | if data: 24 | data = 'server echoes: ' + data 25 | cs.send(data) 26 | else: 27 | break 28 | 29 | s.close() 30 | 31 | 32 | def client(ip, port): 33 | s = socket.socket() 34 | s.connect((ip, int(port))) 35 | 36 | for i in range(10): 37 | new_data = data[i:] + data[:i+1] 38 | s.send(new_data) 39 | print s.recv(1000) 40 | sleep(1) 41 | 42 | s.close() 43 | 44 | if __name__ == '__main__': 45 | if sys.argv[1] == 'server': 46 | server(sys.argv[2]) 47 | elif sys.argv[1] == 'client': 48 | client(sys.argv[2], sys.argv[3]) 49 | -------------------------------------------------------------------------------- /18-http_server_4/tcp_stack_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | 3 | import os 4 | import sys 5 | import string 6 | import socket 7 | import struct 8 | from time import sleep 9 | 10 | data = string.digits + string.lowercase + string.uppercase 11 | 12 | def server(port, filename): 13 | s = socket.socket() 14 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 15 | 16 | s.bind(('0.0.0.0', int(port))) 17 | s.listen(3) 18 | 19 | cs, addr = s.accept() 20 | print addr 21 | 22 | with open(filename, 'wb') as f: 23 | while True: 24 | data = cs.recv(1024) 25 | if data: 26 | f.write(data) 27 | else: 28 | break 29 | 30 | s.close() 31 | 32 | 33 | def client(ip, port, filename): 34 | s = socket.socket() 35 | s.connect((ip, int(port))) 36 | 37 | file_size = os.path.getsize(filename) 38 | send_size = 0 39 | 40 | with open(filename, 'rb') as f: 41 | while True: 42 | data = f.read(1024) 43 | if data: 44 | send_size += sys.getsizeof(data) 45 | print 'send %d Bytes' % (send_size) 46 | s.send(data) 47 | else: 48 | break 49 | sleep(0.01) 50 | 51 | s.close() 52 | 53 | if __name__ == '__main__': 54 | if sys.argv[1] == 'server': 55 | server(sys.argv[2], sys.argv[3]) 56 | elif sys.argv[1] == 'client': 57 | client(sys.argv[2], sys.argv[3], sys.argv[4]) 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 ceba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UCAS-Network-Lab 2 | > 计算机网络研讨课 2021春季 UCAS 3 | 4 | 从数据链路层到应用层的网络协议栈实现。 5 | 6 | ## 目录 7 | * [02-互联网协议实验](02-protocol) 8 | * [03-Socket应用编程实验](03-socket) 9 | * [04-广播网络实验](04-broadcast) 10 | * [05-交换机转发实验](05-switching) 11 | * [06-生成树机制实验](06-stp) 12 | * [07-数据包队列管理实验](07-bufferbloat) 13 | * [09-路由器转发实验](09-router) 14 | * [10-高效IP路由查找实验](10-lookup) 15 | * [11-网络路由实验](11-mopsf) 16 | * [12-网络地址转换实验](12-nat) 17 | * [13-网络传输机制实验一](13-tcp_stack) 18 | * [15-网络传输机制实验二](15-tcp_stack) 19 | * [16-网络传输机制实验三](16-tcp_stack) 20 | * [17-网络传输机制实验四](17-tcp_stack) 21 | * 18-Socket应用移植实验: 22 | * [组合2](18-http_server_2) 23 | * [组合4](18-http_server_4) 24 | --------------------------------------------------------------------------------