├── .editorconfig ├── .gitignore ├── DoS ├── bmv2 │ ├── .vscode │ │ └── settings.json │ ├── README.md │ ├── cleanup.sh │ ├── commands.txt │ ├── p4src │ │ ├── hashes.p4 │ │ ├── headers.p4 │ │ ├── parsers.p4 │ │ ├── syntry.old.p4 │ │ └── syntry.p4 │ ├── run_demo.sh │ ├── run_switch.py │ ├── sswitch_CLI.sh │ ├── syntry.json │ ├── topo.py │ └── topo.txt └── tofino │ ├── README.md │ ├── qy_build.sh │ ├── syntry.p4 │ ├── syntry2.p4 │ ├── syntry3.p4 │ ├── test.py │ └── test.pyc └── README.md /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # all files 5 | [*] 6 | indent_style = tab 7 | indent_size = 4 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #for vim temp files 2 | *.swp 3 | *.swo 4 | #for pacp 5 | *.pcap 6 | #for dot 7 | *.dot 8 | *~ 9 | #png 10 | *.png 11 | *.json 12 | 13 | .vscode/ -------------------------------------------------------------------------------- /DoS/bmv2/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.linting.pylintEnabled": false 3 | } -------------------------------------------------------------------------------- /DoS/bmv2/README.md: -------------------------------------------------------------------------------- 1 | # BMv2 demo 2 | This is a demo with all features mentioned implemented using p4-14 standard. Source code in this folder is designed for running in BMv2 enviornment. 3 | ## Overview 4 | We implement a switch that can mitigate most type of DDoS attacks, including a filter, an anti-spoofing module and an unspoofing attack defense module. Most of the mechanisms are implemented in the data plane of programmable switches. 5 | 6 | ## Design 7 | ### Modeling 8 | We set up a relatively simple model with h1-s1-h2 topology using mininet. We assume that h1 first initializes a session request(send the SYN packet) to h2 and after the three-way handshake, the tcp session is set up and successive packets such as http request will travel between h1 and h2 through the switch. 9 | ### Workflow 10 | 1. H1 initializes a session and sends the syn packet. The switch will capture the packet and send back the SYN/ACK packet to h1 with certain SEQ# without transmiting any message to h2. 11 | 2. When h1 sends the ack packet back, the switch validates its ACK# and sends SYN packet to h2 to establish a session with h2. After the session between h2 is set up, the switch will relay the session A (between h1 and s1) and session B (between s1 and h2). 12 | 3. Additionally, the program will watch for every SYN packet passing through and every connection established. The SYN proxy module will start up or shut down automatically according to the speed of SYN packets sent to the switch and the difference of the number between SYN packets and valid ACK packets during TCP handshake. Meanwhile, two sketches are responsible for watching for hosts who is holding up too much connections or sending too much data in a certain period. 13 | ## Test 14 | To test this demo, you are supposed to set up a topology on **mininet** where we run the switch. 15 | 16 | 17 | 1. Run `run_demo.sh` to start the switch on the topology defined in `topo.py`. 18 | 2. Run a simple web server and client according to [mininet walkthrough](http://mininet.org/walkthrough/#run-a-simple-web-server-and-client). 19 | 3. `run_switch.py` contains most of the measurement mechanisms. SYN proxy is on by default. 20 | 21 | 22 | 23 | ## Source Code 24 | `p4src/syntry.p4` This is the p4 source code. 25 | 26 | `topo.py` This script will set up the topology of this model and starts the CLI of p4 switch. 27 | 28 | `server.py` This script will run a simple server on the host. 29 | 30 | `run_demo.sh` Start the switch on the topology defined in `topo.py` without log. 31 | 32 | `commands.txt` There are table entries here, which will be loaded into the swtich by `topo.py`. You can also add the entries manually through CLI. 33 | 34 | `cleanup` Clean up the environment such as the virtual network interfaces. 35 | 36 | -------------------------------------------------------------------------------- /DoS/bmv2/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2013-present Barefoot Networks, Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | if [[ $EUID -ne 0 ]]; then 18 | echo "This script should be run using sudo or as the root user" 19 | exit 1 20 | fi 21 | 22 | killall lt-simple_switch &> /dev/null 23 | mn -c &> /dev/null 24 | intf="cpu-veth-0" 25 | if ip link show $intf &> /dev/null; then 26 | ip link delete $intf type veth 27 | fi 28 | -------------------------------------------------------------------------------- /DoS/bmv2/commands.txt: -------------------------------------------------------------------------------- 1 | table_set_default syn_meter_table syn_meter_action 2 | table_set_default check_no_proxy_table read_no_proxy_table_entry_value 3 | table_set_default sub_delta_to_seq_table sub_delta_to_seq 4 | table_set_default add_delta_to_ack_table add_delta_to_ack 5 | table_set_default check_syn_proxy_table read_syn_proxy_table_entry_value 6 | table_set_default calculate_syn_cookie_table _drop 7 | table_set_default check_proxy_status_table turn_off_proxy 8 | table_set_default drop_table _drop 9 | table_set_default empty_conn_in_proxy_table_table empty_conn_in_proxy_table 10 | table_set_default open_window_table open_window 11 | table_set_default reply_sa_table reply_sa 12 | table_set_default confirm_connection_table confirm_connection 13 | table_set_default mark_forward_normally_table mark_forward_normally 14 | table_set_default mark_no_conn_table mark_no_conn_could_drop 15 | table_set_default mark_no_proxy_table _no_op 16 | 17 | table_set_default ipv4_lpm_table _drop 18 | table_set_default forward_table _drop 19 | table_set_default send_frame _drop 20 | 21 | 22 | 23 | table_add mark_no_proxy_table mark_has_syn 0 0x0&&&0x0 => 1 24 | table_add mark_no_proxy_table mark_forward_normally 1 0x02&&&0x3f => 1 25 | table_add mark_no_proxy_table mark_forward_normally 1 0x12&&&0x3f => 1 26 | table_add mark_no_proxy_table mark_forward_normally 1 0x04&&&0x04 => 1 27 | table_add mark_no_proxy_table mark_has_ack 1 0x10&&&0x12 => 1 28 | table_add mark_no_proxy_table mark_no_conn 1 0x11&&&0x11 => 1 29 | table_add mark_no_proxy_table mark_has_syn 2 0x11&&&0x11 => 10 30 | table_add mark_no_proxy_table mark_forward_normally 2 0x00&&&0x00 => 1 31 | 32 | table_add calculate_syn_cookie_table calculate_syn_cookie_from_client 0x02&&&0x02 => 0xe 0xf 1 33 | table_add calculate_syn_cookie_table calculate_syn_cookie_from_client 0x10&&&0x10 => 0xe 0xf 1 34 | table_add calculate_syn_cookie_table calculate_syn_cookie_from_server 0x12&&&0x12 => 0xe 0xf 2 35 | 36 | table_add ipv4_lpm_table set_nhop 10.0.0.10/32 => 10.0.0.10 1 37 | table_add ipv4_lpm_table set_nhop 11.0.0.10/32 => 11.0.0.10 2 38 | 39 | table_add forward_table set_dmac 10.0.0.10 => 00:00:00:00:00:10 40 | table_add forward_table set_dmac 11.0.0.10 => 00:00:00:00:00:20 41 | 42 | table_add send_frame rewrite_mac 1 => 00:00:00:00:00:01 43 | table_add send_frame rewrite_mac 2 => 00:00:00:00:00:02 44 | 45 | mirroring_add 500 11 46 | 47 | meter_array_set_rates syn_meter 0.0000005:1 0.00001:1 -------------------------------------------------------------------------------- /DoS/bmv2/p4src/hashes.p4: -------------------------------------------------------------------------------- 1 | //******** 2 | //********HASHES******** 3 | //******** 4 | 5 | field_list tcp_five_tuple_list{ 6 | ipv4.src_addr; 7 | ipv4.dst_addr; 8 | tcp.srcPort; 9 | tcp.dstPort; 10 | ipv4.protocol; 11 | } 12 | field_list_calculation tcp_five_tuple_hash { 13 | input { 14 | tcp_five_tuple_list; 15 | } 16 | algorithm : csum16; 17 | output_width : 13; 18 | } 19 | 20 | field_list src_ip_list { 21 | ipv4.src_addr; 22 | } 23 | field_list_calculation src_ip_hash { 24 | input { 25 | src_ip_list; 26 | } 27 | algorithm : crc16; 28 | output_width : 16; 29 | } 30 | field_list dst_ip_list { 31 | ipv4.dst_addr; 32 | } 33 | field_list_calculation dst_ip_hash { 34 | input { 35 | dst_ip_list; 36 | } 37 | algorithm : crc16; 38 | output_width : 16; 39 | } 40 | 41 | field_list syn_cookie_key1_list{ 42 | ipv4.src_addr; 43 | ipv4.dst_addr; 44 | tcp.srcPort; 45 | tcp.dstPort; 46 | ipv4.protocol; 47 | meta.cookie_key1; 48 | } 49 | field_list_calculation syn_cookie_key1_calculation { 50 | input { 51 | syn_cookie_key1_list; 52 | } 53 | algorithm : crc32; 54 | output_width : 32; 55 | } 56 | 57 | field_list syn_cookie_key2_list{ 58 | ipv4.src_addr; 59 | ipv4.dst_addr; 60 | tcp.srcPort; 61 | tcp.dstPort; 62 | ipv4.protocol; 63 | meta.cookie_key2; 64 | } 65 | field_list_calculation syn_cookie_key2_calculation { 66 | input { 67 | syn_cookie_key2_list; 68 | } 69 | algorithm : crc32; 70 | output_width : 32; 71 | } 72 | 73 | field_list syn_cookie_key1_reverse_list{ 74 | ipv4.dst_addr; 75 | ipv4.src_addr; 76 | tcp.dstPort; 77 | tcp.srcPort; 78 | ipv4.protocol; 79 | meta.cookie_key1; 80 | } 81 | field_list_calculation syn_cookie_key1_reverse_calculation { 82 | input { 83 | syn_cookie_key1_reverse_list; 84 | } 85 | algorithm : crc32; 86 | output_width : 32; 87 | } 88 | 89 | field_list syn_cookie_key2_reverse_list{ 90 | ipv4.dst_addr; 91 | ipv4.src_addr; 92 | tcp.dstPort; 93 | tcp.srcPort; 94 | ipv4.protocol; 95 | meta.cookie_key2; 96 | } 97 | field_list_calculation syn_cookie_key2_reverse_calculation { 98 | input { 99 | syn_cookie_key2_reverse_list; 100 | } 101 | algorithm : crc32; 102 | output_width : 32; 103 | } 104 | 105 | field_list ip_hash_fields { 106 | ipv4.src_addr; 107 | // ipv4.dst_addr; 108 | } 109 | field_list_calculation heavy_hitter_hash0{ 110 | input { 111 | ip_hash_fields; 112 | } 113 | algorithm:csum16; 114 | output_width:8; 115 | } 116 | field_list_calculation heavy_hitter_hash1{ 117 | input{ 118 | ip_hash_fields; 119 | } 120 | algorithm:crc16; 121 | output_width:8; 122 | } 123 | //********HASHES END******** -------------------------------------------------------------------------------- /DoS/bmv2/p4src/headers.p4: -------------------------------------------------------------------------------- 1 | 2 | //******** 3 | //********HEADERS******** 4 | //******** 5 | header_type ethernet_t { 6 | fields { 7 | dst_addr : 48; 8 | src_addr : 48; 9 | etherType : 16; 10 | } 11 | } 12 | 13 | header_type ipv4_t { 14 | fields { 15 | version : 4; 16 | ihl : 4; 17 | diffserv : 8; 18 | totalLen : 16; 19 | identification : 16; 20 | flags : 3; 21 | fragOffset : 13; 22 | ttl : 8; 23 | protocol : 8; 24 | hdrChecksum : 16; 25 | src_addr : 32; 26 | dst_addr: 32; 27 | } 28 | } 29 | 30 | header_type tcp_t { 31 | fields { 32 | srcPort : 16; 33 | dstPort : 16; 34 | seq_no : 32; 35 | ack_no : 32; 36 | dataOffset : 4; 37 | res : 6; 38 | flags : 6; 39 | window : 16; 40 | checksum : 16; 41 | urgentPtr : 16; 42 | } 43 | } 44 | 45 | // header cpu_header_t cpu_header; 46 | header ethernet_t ethernet; 47 | header ipv4_t ipv4; 48 | header tcp_t tcp; 49 | //********HEADERS END******** 50 | -------------------------------------------------------------------------------- /DoS/bmv2/p4src/parsers.p4: -------------------------------------------------------------------------------- 1 | 2 | //******** 3 | //********PARSERS******** 4 | //******** 5 | 6 | // parser: start 7 | parser start { 8 | set_metadata(meta.to_drop, TRUE); 9 | set_metadata(meta.in_black_list, FALSE); 10 | return parse_ethernet; 11 | } 12 | 13 | #define ETHERTYPE_IPV4 0x0800 14 | 15 | // parser: ethernet 16 | parser parse_ethernet { 17 | extract(ethernet); 18 | set_metadata(meta.eth_da,ethernet.dst_addr); 19 | set_metadata(meta.eth_sa,ethernet.src_addr); 20 | return select(latest.etherType) { 21 | ETHERTYPE_IPV4 : parse_ipv4; 22 | default: ingress; 23 | } 24 | } 25 | 26 | // checksum: ipv4 27 | field_list ipv4_checksum_list { 28 | ipv4.version; 29 | ipv4.ihl; 30 | ipv4.diffserv; 31 | ipv4.totalLen; 32 | ipv4.identification; 33 | ipv4.flags; 34 | ipv4.fragOffset; 35 | ipv4.ttl; 36 | ipv4.protocol; 37 | ipv4.src_addr; 38 | ipv4.dst_addr; 39 | } 40 | 41 | field_list_calculation ipv4_checksum { 42 | input { 43 | ipv4_checksum_list; 44 | } 45 | algorithm : csum16; 46 | output_width : 16; 47 | } 48 | 49 | calculated_field ipv4.hdrChecksum { 50 | verify ipv4_checksum; 51 | update ipv4_checksum; 52 | } 53 | 54 | #define IP_PROT_TCP 0x06 55 | 56 | // parser: ipv4 57 | parser parse_ipv4 { 58 | extract(ipv4); 59 | 60 | set_metadata(meta.ipv4_sa, ipv4.src_addr); 61 | set_metadata(meta.ipv4_da, ipv4.dst_addr); 62 | set_metadata(meta.tcp_length, ipv4.totalLen - 20); 63 | return select(ipv4.protocol) { 64 | IP_PROT_TCP : parse_tcp; 65 | default: ingress; 66 | } 67 | } 68 | 69 | // checksum: tcp 70 | field_list tcp_checksum_list { 71 | ipv4.src_addr; 72 | ipv4.dst_addr; 73 | 8'0; 74 | ipv4.protocol; 75 | meta.tcp_length; 76 | tcp.srcPort; 77 | tcp.dstPort; 78 | tcp.seq_no; 79 | tcp.ack_no; 80 | tcp.dataOffset; 81 | tcp.res; 82 | tcp.flags; 83 | tcp.window; 84 | tcp.urgentPtr; 85 | payload; 86 | } 87 | 88 | field_list_calculation tcp_checksum { 89 | input { 90 | tcp_checksum_list; 91 | } 92 | algorithm : csum16; 93 | output_width : 16; 94 | } 95 | 96 | calculated_field tcp.checksum { 97 | verify tcp_checksum if(valid(tcp)); 98 | update tcp_checksum if(valid(tcp)); 99 | } 100 | 101 | // parser: tcp 102 | parser parse_tcp { 103 | extract(tcp); 104 | set_metadata(meta.tcp_sp, tcp.srcPort); 105 | set_metadata(meta.tcp_dp, tcp.dstPort); 106 | // set_metadata(meta.tcp_flags, tcp.flags); 107 | set_metadata(meta.tcp_seq_no, tcp.seq_no); 108 | set_metadata(meta.tcp_ack_no, tcp.ack_no); 109 | set_metadata(meta.to_drop, TRUE); 110 | return ingress; 111 | } 112 | //********PARSERS END******** -------------------------------------------------------------------------------- /DoS/bmv2/p4src/syntry.old.p4: -------------------------------------------------------------------------------- 1 | 2 | // for syn proxy 3 | #define PROXY_OFF 0 4 | #define PROXY_ON 1 5 | // for tcp flags 6 | #define TCP_FLAG_URG 0x20 7 | #define TCP_FLAG_ACK 0x10 8 | #define TCP_FLAG_PSH 0x08 9 | #define TCP_FLAG_RST 0x04 10 | #define TCP_FLAG_SYN 0x02 11 | #define TCP_FLAG_FIN 0x01 12 | // for clone packets 13 | #define CPU_SESSION 500 14 | // for meter 15 | #define METER_COLOR_GREEN 0 16 | #define METER_COLOR_YELLOW 1 17 | #define METER_COLOR_RED 2 18 | 19 | #define FALSE 0 20 | #define TRUE 1 21 | 22 | 23 | #define CONN_NOT_EXIST 00 24 | #define CONN_HAS_SYN 01 25 | #define CONN_HAS_ACK 10 26 | #define INVALID 0x0 27 | #define VALID 0x1 28 | 29 | 30 | //******** 31 | //********HEADERS******** 32 | //******** 33 | header_type ethernet_t { 34 | fields { 35 | dstAddr : 48; 36 | srcAddr : 48; 37 | etherType : 16; 38 | } 39 | } 40 | 41 | header_type ipv4_t { 42 | fields { 43 | version : 4; 44 | ihl : 4; 45 | diffserv : 8; 46 | totalLen : 16; 47 | identification : 16; 48 | flags : 3; 49 | fragOffset : 13; 50 | ttl : 8; 51 | protocol : 8; 52 | hdrChecksum : 16; 53 | srcAddr : 32; 54 | dstAddr: 32; 55 | } 56 | } 57 | 58 | header_type tcp_t { 59 | fields { 60 | srcPort : 16; 61 | dstPort : 16; 62 | seq_no : 32; 63 | ack_no : 32; 64 | dataOffset : 4; 65 | res : 6; 66 | flags : 6; 67 | window : 16; 68 | checksum : 16; 69 | urgentPtr : 16; 70 | } 71 | } 72 | 73 | // header cpu_header_t cpu_header; 74 | header ethernet_t ethernet; 75 | header ipv4_t ipv4; 76 | header tcp_t tcp; 77 | //********HEADERS END******** 78 | 79 | 80 | 81 | //******** 82 | //********PARSERS******** 83 | //******** 84 | 85 | // parser: start 86 | parser start { 87 | set_metadata(meta.to_drop, TRUE); 88 | return parse_ethernet; 89 | } 90 | 91 | #define ETHERTYPE_IPV4 0x0800 92 | 93 | // parser: ethernet 94 | parser parse_ethernet { 95 | extract(ethernet); 96 | set_metadata(meta.eth_da,ethernet.dstAddr); 97 | set_metadata(meta.eth_sa,ethernet.srcAddr); 98 | return select(latest.etherType) { 99 | ETHERTYPE_IPV4 : parse_ipv4; 100 | default: ingress; 101 | } 102 | } 103 | 104 | // checksum: ipv4 105 | field_list ipv4_checksum_list { 106 | ipv4.version; 107 | ipv4.ihl; 108 | ipv4.diffserv; 109 | ipv4.totalLen; 110 | ipv4.identification; 111 | ipv4.flags; 112 | ipv4.fragOffset; 113 | ipv4.ttl; 114 | ipv4.protocol; 115 | ipv4.srcAddr; 116 | ipv4.dstAddr; 117 | } 118 | 119 | field_list_calculation ipv4_checksum { 120 | input { 121 | ipv4_checksum_list; 122 | } 123 | algorithm : csum16; 124 | output_width : 16; 125 | } 126 | 127 | calculated_field ipv4.hdrChecksum { 128 | verify ipv4_checksum; 129 | update ipv4_checksum; 130 | } 131 | 132 | #define IP_PROT_TCP 0x06 133 | 134 | // parser: ipv4 135 | parser parse_ipv4 { 136 | extract(ipv4); 137 | 138 | set_metadata(meta.ipv4_sa, ipv4.srcAddr); 139 | set_metadata(meta.ipv4_da, ipv4.dstAddr); 140 | set_metadata(meta.tcp_length, ipv4.totalLen - 20); 141 | return select(ipv4.protocol) { 142 | IP_PROT_TCP : parse_tcp; 143 | default: ingress; 144 | } 145 | } 146 | 147 | // checksum: tcp 148 | field_list tcp_checksum_list { 149 | ipv4.srcAddr; 150 | ipv4.dstAddr; 151 | 8'0; 152 | ipv4.protocol; 153 | meta.tcp_length; 154 | tcp.srcPort; 155 | tcp.dstPort; 156 | tcp.seq_no; 157 | tcp.ack_no; 158 | tcp.dataOffset; 159 | tcp.res; 160 | tcp.flags; 161 | tcp.window; 162 | tcp.urgentPtr; 163 | payload; 164 | } 165 | 166 | field_list_calculation tcp_checksum { 167 | input { 168 | tcp_checksum_list; 169 | } 170 | algorithm : csum16; 171 | output_width : 16; 172 | } 173 | 174 | calculated_field tcp.checksum { 175 | verify tcp_checksum if(valid(tcp)); 176 | update tcp_checksum if(valid(tcp)); 177 | } 178 | 179 | // parser: tcp 180 | parser parse_tcp { 181 | extract(tcp); 182 | set_metadata(meta.tcp_sp, tcp.srcPort); 183 | set_metadata(meta.tcp_dp, tcp.dstPort); 184 | // set_metadata(meta.tcp_flags, tcp.flags); 185 | set_metadata(meta.tcp_seq_no, tcp.seq_no); 186 | set_metadata(meta.tcp_ack_no, tcp.ack_no); 187 | return ingress; 188 | } 189 | //********PARSERS END******** 190 | 191 | 192 | //******** 193 | //********METADATA******** 194 | //******** 195 | 196 | header_type meta_t { 197 | fields { 198 | // ethernet information 199 | eth_sa:48; // eth src addr 200 | eth_da:48; // eth des addr 201 | // ip information 202 | ipv4_sa : 32; // ipv4 src addr 203 | ipv4_da : 32; // ipv4 des addr 204 | // tcp information 205 | tcp_sp : 16; // tcp src port 206 | tcp_dp : 16; // tcp des port 207 | tcp_length : 16; // tcp packet length 208 | tcp_ack_no:32; 209 | tcp_seq_no:32; 210 | 211 | // tcp 5-tuple hash 212 | tcp_digest : 13; 213 | 214 | // forward information 215 | nhop_ipv4 : 32; // ipv4 next hop 216 | 217 | // syn meter result (3 colors) 218 | syn_meter_result : 2; // METER_COLOR_RED, METER_COLOR_YELLOW, METER_COLOR_GREEN 219 | syn_proxy_status : 1; // 0 for PROXY_OFF, 1 for PROXY_ON 220 | 221 | // seq# offset 222 | seq_no_offset : 32; 223 | 224 | // for syn-cookie 225 | cookie_key1 : 32; 226 | cookie_key2 : 32; 227 | cookie_val1 : 32; // always use val1 first 228 | cookie_val2 : 32; 229 | 230 | // when receiving syn+ack from server 231 | cookie_val_in_register : 33; 232 | offset_val_in_register : 33; 233 | 234 | // for check_no_proxy_table 235 | no_proxy_table_hash_val : 13; 236 | no_proxy_table_entry_val : 2; 237 | 238 | // for check_syn_proxy_table 239 | syn_proxy_table_hash_val : 13; 240 | syn_proxy_table_entry_val : 39; 241 | 242 | to_drop : 1; 243 | } 244 | 245 | } 246 | metadata meta_t meta; 247 | 248 | 249 | // field_list copy_to_cpu_fields { 250 | // standard_metadata; 251 | // meta; 252 | // } 253 | //********METADATA ENDS******** 254 | 255 | 256 | 257 | //********REGISTERS******** 258 | //********11 * 8192 byte = 88KB in total******** 259 | counter syn_counter { 260 | type : packets; 261 | static : reply_sa_table; 262 | instance_count : 1; 263 | } 264 | counter valid_ack_counter { 265 | type : packets; 266 | static : confirm_connection_table; 267 | instance_count : 1; 268 | } 269 | register no_proxy_table { 270 | width : 2; 271 | instance_count : 8192; 272 | } 273 | register syn_proxy_table { 274 | /* 275 | |32 bits offset|6 bits port(server port)|1 bit is_valid| 276 | */ 277 | width : 39; // 32 bit offset + 6 bit port + 1 bit is_valid 278 | instance_count : 8192; 279 | } 280 | //********REGISTERS ENDS******** 281 | 282 | 283 | field_list tcp_five_tuple_list{ 284 | ipv4.srcAddr; 285 | ipv4.dstAddr; 286 | tcp.srcPort; 287 | tcp.dstPort; 288 | ipv4.protocol; 289 | } 290 | field_list_calculation tcp_five_tuple_hash { 291 | input { 292 | tcp_five_tuple_list; 293 | } 294 | algorithm : csum16; 295 | output_width : 16; 296 | } 297 | 298 | action _no_op(){ 299 | no_op(); 300 | } 301 | 302 | action _drop() { 303 | modify_field(meta.to_drop, TRUE); 304 | modify_field(ipv4.dstAddr, 0); 305 | drop(); 306 | } 307 | 308 | // action _resubmit() 309 | // { 310 | // resubmit(resubmit_FL); 311 | // } 312 | 313 | 314 | //********for syn_meter_table******** 315 | // { 316 | meter syn_meter { 317 | type : packets; 318 | instance_count : 1; 319 | } 320 | action syn_meter_action() { 321 | // read syn proxy status into metadata 322 | execute_meter(syn_meter, 0, meta.syn_proxy_status); 323 | } 324 | table syn_meter_table { 325 | actions { 326 | syn_meter_action; 327 | } 328 | } 329 | // } 330 | //********for check_no_proxy_table******** 331 | // { 332 | action read_no_proxy_table_entry_value() { 333 | modify_field_with_hash_based_offset(meta.no_proxy_table_hash_val, 0, tcp_five_tuple_hash, 13); 334 | register_read(meta.no_proxy_table_entry_val, no_proxy_table, meta.no_proxy_table_hash_val); 335 | } 336 | table check_no_proxy_table { 337 | actions { 338 | read_no_proxy_table_entry_value; 339 | } 340 | } 341 | // } 342 | //********for sub_delta_to_seq_table******** 343 | // { 344 | action sub_delta_to_seq() { 345 | modify_field(meta.to_drop, FALSE); 346 | subtract_from_field(tcp.seq_no, meta.syn_proxy_table_entry_val >> 7); 347 | } 348 | table sub_delta_to_seq_table { 349 | actions { 350 | sub_delta_to_seq; 351 | } 352 | } 353 | // } 354 | //********for add_delta_to_ack_table******** 355 | // { 356 | action add_delta_to_ack() { 357 | modify_field(meta.to_drop, FALSE); 358 | add_to_field(tcp.ack_no, meta.syn_proxy_table_entry_val >> 7); 359 | } 360 | table add_delta_to_ack_table { 361 | actions { 362 | add_delta_to_ack; 363 | } 364 | } 365 | // } 366 | //********for check_syn_proxy_table******** 367 | // { 368 | action read_syn_proxy_table_entry_value() { 369 | modify_field_with_hash_based_offset(meta.syn_proxy_table_hash_val, 0, tcp_five_tuple_hash, 13); 370 | register_read(meta.syn_proxy_table_entry_val, syn_proxy_table, meta.syn_proxy_table_hash_val); 371 | } 372 | table check_syn_proxy_table { 373 | actions { 374 | read_syn_proxy_table_entry_value; 375 | } 376 | } 377 | // } 378 | //********for calculate_syn_cookie_table******** 379 | // { 380 | field_list syn_cookie_key1_list{ 381 | ipv4.srcAddr; 382 | ipv4.dstAddr; 383 | tcp.srcPort; 384 | tcp.dstPort; 385 | ipv4.protocol; 386 | meta.cookie_key1; 387 | } 388 | field_list_calculation syn_cookie_key1_calculation { 389 | input { 390 | syn_cookie_key1_list; 391 | } 392 | algorithm : crc32; 393 | output_width : 32; 394 | } 395 | 396 | 397 | field_list syn_cookie_key2_list{ 398 | ipv4.srcAddr; 399 | ipv4.dstAddr; 400 | tcp.srcPort; 401 | tcp.dstPort; 402 | ipv4.protocol; 403 | meta.cookie_key2; 404 | } 405 | field_list_calculation syn_cookie_key2_calculation { 406 | input { 407 | syn_cookie_key2_list; 408 | } 409 | algorithm : crc32; 410 | output_width : 32; 411 | } 412 | 413 | 414 | field_list syn_cookie_key1_reverse_list{ 415 | ipv4.dstAddr; 416 | ipv4.srcAddr; 417 | tcp.dstPort; 418 | tcp.srcPort; 419 | ipv4.protocol; 420 | meta.cookie_key1; 421 | } 422 | field_list_calculation syn_cookie_key1_reverse_calculation { 423 | input { 424 | syn_cookie_key1_reverse_list; 425 | } 426 | algorithm : crc32; 427 | output_width : 32; 428 | } 429 | 430 | 431 | field_list syn_cookie_key2_reverse_list{ 432 | ipv4.dstAddr; 433 | ipv4.srcAddr; 434 | tcp.dstPort; 435 | tcp.srcPort; 436 | ipv4.protocol; 437 | meta.cookie_key2; 438 | } 439 | field_list_calculation syn_cookie_key2_reverse_calculation { 440 | input { 441 | syn_cookie_key2_reverse_list; 442 | } 443 | algorithm : crc32; 444 | output_width : 32; 445 | } 446 | // use a simpler version of syn-cookie 447 | // timestamp(for connection timeout), MSS(for ack packet reconstruction) not implemented 448 | action calculate_syn_cookie_from_client(key1, key2){ 449 | modify_field(meta.cookie_key1, key1); 450 | modify_field(meta.cookie_key2, key2); 451 | modify_field_with_hash_based_offset(meta.cookie_val1, 0, syn_cookie_key1_calculation, 32); 452 | modify_field_with_hash_based_offset(meta.cookie_val2, 0, syn_cookie_key2_calculation, 32); 453 | } 454 | action calculate_syn_cookie_from_server(key1, key2){ 455 | modify_field(meta.cookie_key1, key1); 456 | modify_field(meta.cookie_key2, key2); 457 | modify_field_with_hash_based_offset(meta.cookie_val1, 0, syn_cookie_key1_reverse_calculation, 32); 458 | modify_field_with_hash_based_offset(meta.cookie_val2, 0, syn_cookie_key2_reverse_calculation, 32); 459 | } 460 | table calculate_syn_cookie_table { 461 | reads { 462 | // for syn & ack, it is definitely from client 463 | // syn+ack comes from server 464 | tcp.flags : ternary; 465 | } 466 | actions { 467 | _drop; 468 | calculate_syn_cookie_from_client; 469 | calculate_syn_cookie_from_server; 470 | } 471 | } 472 | // } 473 | //********for check_proxy_status_table******** 474 | // { 475 | action turn_on_proxy() { 476 | modify_field(meta.syn_proxy_status, PROXY_ON); 477 | 478 | } 479 | action turn_off_proxy() { 480 | modify_field(meta.syn_proxy_status, PROXY_OFF); 481 | } 482 | table check_proxy_status_table { 483 | actions { 484 | turn_on_proxy; 485 | turn_off_proxy; 486 | _no_op; 487 | } 488 | } 489 | // } 490 | //********for drop_table******** 491 | // { 492 | table drop_table { 493 | actions { 494 | _drop; 495 | } 496 | } 497 | // } 498 | //********for open_window_table******** 499 | // { 500 | action open_window() { 501 | modify_field(meta.to_drop, FALSE); 502 | // set tcp seq# to syn cookie value 503 | modify_field(meta.seq_no_offset, (meta.syn_proxy_table_entry_val & 0x7fffffff80) >> 7); 504 | // set seq_no_offset 505 | // TODO: by default, we reckon tcp.seq_no > cookie_val 506 | subtract(meta.seq_no_offset, tcp.seq_no, meta.seq_no_offset); 507 | modify_field(tcp.seq_no, (meta.syn_proxy_table_entry_val & 0x7fffffff80) >> 7); 508 | // write offset, port, is_Valid into syn_proxy_table 509 | register_write(syn_proxy_table, meta.syn_proxy_table_hash_val, (meta.seq_no_offset << 7) | (standard_metadata.ingress_port << 1) | 0x1); 510 | } 511 | table open_window_table { 512 | actions { 513 | open_window; 514 | } 515 | } 516 | // } 517 | //********for reply_sa_table******** 518 | // { 519 | action reply_sa() { 520 | modify_field(meta.to_drop, FALSE); 521 | // reply client with syn+ack and a certain seq no, and window size 0 522 | 523 | // no need to exchange ethernet values 524 | // since forward table will do this for us 525 | // // exchange src-eth, dst-eth 526 | // modify_field(ethernet.srcAddr, meta.eth_da); 527 | // modify_field(ethernet.dstAddr, meta.eth_sa); 528 | // exchange src-ip, dst-ip 529 | modify_field(ipv4.srcAddr, meta.ipv4_da); 530 | modify_field(ipv4.dstAddr, meta.ipv4_sa); 531 | // exchange src-port, dst-port 532 | modify_field(tcp.srcPort, meta.tcp_dp); 533 | modify_field(tcp.dstPort, meta.tcp_sp); 534 | // set tcp flags: SYN+ACK 535 | modify_field(tcp.flags, TCP_FLAG_ACK | TCP_FLAG_SYN); 536 | // set ack# to be seq# + 1 537 | modify_field(tcp.ack_no, tcp.seq_no + 1); 538 | // set seq# to be a hash val 539 | modify_field(tcp.seq_no, meta.cookie_val1); 540 | // set window to be 0. 541 | // stop client from transferring data 542 | modify_field(tcp.window, 0); 543 | // count: syn packet 544 | count(syn_counter, 0); 545 | } 546 | table reply_sa_table { 547 | actions { 548 | reply_sa; 549 | } 550 | } 551 | // } 552 | //********for confirm_connection_table******** 553 | // { 554 | action confirm_connection() { 555 | // handshake with client finished, start establishing connection with server 556 | modify_field(meta.to_drop, FALSE); 557 | // syn_proxy_table : set seq# 558 | register_write(syn_proxy_table, meta.syn_proxy_table_hash_val, (tcp.ack_no - 1) << 7); 559 | // set seq# to be seq# - 1 (same as the beginning syn packet seq#) 560 | modify_field(tcp.seq_no, tcp.seq_no - 1); 561 | // set flag: syn 562 | modify_field(tcp.flags, TCP_FLAG_SYN); 563 | // set ack# 0 (optional) 564 | modify_field(tcp.ack_no, 0); 565 | // count: valid ack 566 | count(valid_ack_counter, 0); 567 | } 568 | table confirm_connection_table { 569 | actions { 570 | confirm_connection; 571 | } 572 | } 573 | // } 574 | //********for mark_no_conn_table******** 575 | // { 576 | action mark_no_conn() { 577 | modify_field(meta.to_drop, FALSE); 578 | register_write(no_proxy_table, meta.no_proxy_table_hash_val, CONN_NOT_EXIST); 579 | } 580 | table mark_no_conn_table { 581 | actions { 582 | mark_no_conn; 583 | } 584 | } 585 | // } 586 | //********for mark_has_syn_table******** 587 | // { 588 | action mark_has_syn() { 589 | modify_field(meta.to_drop, FALSE); 590 | register_write(no_proxy_table, meta.no_proxy_table_hash_val, CONN_HAS_SYN); 591 | } 592 | table mark_has_syn_table { 593 | actions { 594 | mark_has_syn; 595 | } 596 | } 597 | // } 598 | //********for mark_has_ack_table******** 599 | // { 600 | action mark_has_ack() { 601 | modify_field(meta.to_drop, FALSE); 602 | register_write(no_proxy_table, meta.no_proxy_table_hash_val, CONN_HAS_ACK); 603 | } 604 | table mark_has_ack_table { 605 | actions { 606 | mark_has_ack; 607 | } 608 | } 609 | // } 610 | //********for mark_foward_normally_table******** 611 | // { 612 | action mark_foward_normally() { 613 | modify_field(meta.to_drop, FALSE); 614 | } 615 | table mark_foward_normally_table { 616 | actions { 617 | mark_foward_normally; 618 | } 619 | } 620 | // } 621 | //********for ipv4_lpm_table******** 622 | // { 623 | action set_nhop(nhop_ipv4, port) { 624 | modify_field(meta.nhop_ipv4, nhop_ipv4); 625 | modify_field(standard_metadata.egress_spec, port); 626 | add_to_field(ipv4.ttl, -1); 627 | } 628 | table ipv4_lpm_table { 629 | reads { 630 | ipv4.dstAddr : lpm; 631 | } 632 | actions { 633 | set_nhop; 634 | _drop; 635 | } 636 | size: 1024; 637 | } 638 | // } 639 | 640 | 641 | //********for forward_table******** 642 | // { 643 | action set_dmac(dmac) { 644 | modify_field(ethernet.dstAddr, dmac); 645 | } 646 | table forward_table { 647 | reads { 648 | meta.nhop_ipv4 : exact; 649 | } 650 | actions { 651 | set_dmac; 652 | _drop; 653 | } 654 | size: 512; 655 | } 656 | // } 657 | 658 | 659 | control syn_proxy { 660 | // syn proxy on 661 | // no need for session check since we use stateless SYN-cookie method 662 | 663 | // whether the packet is an ACK, SYN or SYN+ACK 664 | // syn-cookie will be used 665 | // it must be calculated. 666 | // if it is not one of the three types above, it will be dropped in this table 667 | apply(check_syn_proxy_table); 668 | if(meta.syn_proxy_table_entry_val & 0x1 == VALID){ 669 | if(standard_metadata.ingress_port == (meta.syn_proxy_table_entry_val & 0x7e) >> 1){ 670 | // it's from server 671 | // seq# - delta 672 | apply(sub_delta_to_seq_table); 673 | }else { 674 | // from client 675 | // ack# + delta 676 | apply(add_delta_to_ack_table); 677 | } 678 | }else { 679 | if(tcp.flags & (TCP_FLAG_ACK | TCP_FLAG_SYN) == (TCP_FLAG_ACK | TCP_FLAG_SYN)){ 680 | // syn+ack 681 | apply(open_window_table); 682 | } else{ 683 | apply(calculate_syn_cookie_table); 684 | if(tcp.flags & TCP_FLAG_SYN == TCP_FLAG_SYN){ 685 | // has syn but no ack 686 | // send back syn+ack with special seq# 687 | apply(reply_sa_table); 688 | } else if(tcp.flags & TCP_FLAG_ACK == TCP_FLAG_ACK) { 689 | // has ack but no syn 690 | // make sure ack# is right 691 | if(tcp.ack_no == meta.cookie_val1 + 1 or tcp.ack_no == meta.cookie_val2 + 1){ 692 | apply(confirm_connection_table); 693 | } 694 | } 695 | } 696 | } 697 | } 698 | 699 | control conn_filter { 700 | // writing new logic 701 | // all packets go through the first register array 'no_proxy_table'(2 bits per entry), entries of which are all set to 00 by default 702 | // we're gonna use symmetry hash (hash to the same value for packets of both two directions) 703 | // if the corresponding entry is 01 and the incoming packet is SYN+ACK, then forward normally 704 | // if the corresponding entry is 01 and the incoming packet is ACK, then write 10 into the corresponding entry and forward 705 | // if the corresponding entry is 10 then forward it normally (or write 00 if the packet is FIN ?) 706 | // if the corresponding entry is 00: 707 | // if proxy is off and the incoming packet is SYN, then write 01 into the corresponding entry and forward 708 | // else (proxy is on or incoming packet is not SYN), direct it to syn proxy module 709 | apply(check_no_proxy_table); 710 | if(meta.no_proxy_table_entry_val == CONN_NOT_EXIST){ 711 | if(meta.syn_proxy_status == PROXY_ON or tcp.flags & TCP_FLAG_SYN == 0){ 712 | // direct this packet to syn proxy 713 | syn_proxy(); 714 | }else { 715 | // write 01 into no_proxy_table 716 | apply(mark_has_syn_table); 717 | } 718 | }else if(meta.no_proxy_table_entry_val == CONN_HAS_SYN){ 719 | if(tcp.flags & (TCP_FLAG_ACK | TCP_FLAG_SYN) == (TCP_FLAG_ACK | TCP_FLAG_SYN)){ 720 | // forward normally 721 | apply(mark_foward_normally_table); 722 | }else if (tcp.flags & TCP_FLAG_ACK == TCP_FLAG_ACK){ 723 | // write 10 into no_proxy_table 724 | apply(mark_has_ack_table); 725 | }else if(tcp.flags & TCP_FLAG_FIN == TCP_FLAG_FIN){ 726 | apply(mark_no_conn_table); 727 | } 728 | }else if(meta.no_proxy_table_entry_val == CONN_HAS_ACK){ 729 | if(tcp.flags & TCP_FLAG_FIN == TCP_FLAG_FIN){ 730 | apply(mark_has_syn_table); 731 | }else{ 732 | // forward normally 733 | apply(mark_foward_normally_table); 734 | } 735 | } 736 | } 737 | 738 | control ingress { 739 | // first count syn packets 740 | if(tcp.flags ^ TCP_FLAG_SYN == 0){ 741 | // only has syn 742 | apply(syn_meter_table); 743 | } 744 | // check proxy status 745 | apply(check_proxy_status_table); 746 | conn_filter(); 747 | 748 | if(meta.to_drop == FALSE){ 749 | // TODO: next steps (detect packet size & num from each source ip) 750 | 751 | }else{ 752 | apply(drop_table); 753 | } 754 | apply(ipv4_lpm_table); 755 | apply(forward_table); 756 | } 757 | 758 | 759 | 760 | //********for send_frame******** 761 | // { 762 | action rewrite_mac(smac) { 763 | modify_field(ethernet.srcAddr, smac); 764 | } 765 | table send_frame { 766 | reads { 767 | standard_metadata.egress_port: exact; 768 | } 769 | actions { 770 | rewrite_mac; 771 | _drop; 772 | } 773 | size: 256; 774 | } 775 | // } 776 | 777 | /* 778 | //********for send_to_cpu******** 779 | // { 780 | action do_cpu_encap() { 781 | // add_header does not work 782 | // add_header(cpu_header); 783 | // modify_field(cpu_header.destination, 0xff); 784 | // modify_field(cpu_header.seq_no_offset, meta.seq_no_offset); 785 | modify_field(ethernet.dstAddr, 0xffffffffffff); 786 | modify_field(tcp.seq_no, meta.seq_no_offset); 787 | } 788 | 789 | table send_to_cpu { 790 | actions { do_cpu_encap; } 791 | size : 0; 792 | } 793 | // } 794 | */ 795 | 796 | control egress { 797 | if(standard_metadata.instance_type == 0){ 798 | // not cloned 799 | apply(send_frame); 800 | }else{ 801 | // cloned. 802 | // sent to cpu 803 | // apply(send_to_cpu); 804 | } 805 | } 806 | -------------------------------------------------------------------------------- /DoS/bmv2/p4src/syntry.p4: -------------------------------------------------------------------------------- 1 | // for syn proxy 2 | #define PROXY_OFF 0 3 | #define PROXY_ON 1 4 | // for tcp flags 5 | #define TCP_FLAG_URG 0x20 6 | #define TCP_FLAG_ACK 0x10 7 | #define TCP_FLAG_PSH 0x08 8 | #define TCP_FLAG_RST 0x04 9 | #define TCP_FLAG_SYN 0x02 10 | #define TCP_FLAG_FIN 0x01 11 | #define TCP_FLAG_SA 0x12 12 | // for clone packets 13 | #define CPU_SESSION 500 14 | // for meter 15 | #define METER_COLOR_GREEN 0 16 | #define METER_COLOR_YELLOW 1 17 | #define METER_COLOR_RED 2 18 | 19 | #define FALSE 0 20 | #define TRUE 1 21 | 22 | // for heavy hitter count-min sketch 23 | #define HH_CONN_THRESHOLD 100 // doubled 24 | #define HH_SIZE_THRESHOLD 4096 25 | // for no_proxy_table 26 | #define CONN_NOT_EXIST 0 27 | #define CONN_HAS_SYN 1 28 | #define CONN_HAS_ACK 2 29 | #define INVALID 0x0 30 | #define VALID 0x1 31 | 32 | #define CONFIRMED_CONNECTION_MARK (0x7e)/*last 7 bits*/ 33 | 34 | #define NO_PROXY_TABLE_SIZE 8192 35 | #define SYN_PROXY_TABLE_SIZE 65536 36 | 37 | 38 | #include "headers.p4" 39 | #include "parsers.p4" 40 | #include "hashes.p4" 41 | 42 | //******** 43 | //********METADATA******** 44 | //******** 45 | 46 | header_type meta_t { 47 | fields { 48 | // ethernet information 49 | eth_sa : 48; // eth src addr 50 | eth_da : 48; // eth des addr 51 | // ip information 52 | ipv4_sa : 32; // ipv4 src addr 53 | ipv4_da : 32; // ipv4 des addr 54 | // tcp information 55 | tcp_sp : 16; // tcp src port 56 | tcp_dp : 16; // tcp des port 57 | tcp_length : 16; // tcp packet length 58 | tcp_ack_no:32; 59 | tcp_seq_no:32; 60 | 61 | // forward information 62 | nhop_ipv4 : 32; // ipv4 next hop 63 | 64 | // for control flow 65 | syn_proxy_status : 1; // 0 for PROXY_OFF, 1 for PROXY_ON 66 | to_drop : 1; 67 | in_black_list : 1; 68 | 69 | // seq# offset 70 | seq_no_offset : 32; 71 | 72 | // for syn-cookie 73 | cookie_key1 : 32; 74 | cookie_key2 : 32; 75 | cookie_val1 : 32; // always use val1 first 76 | cookie_val2 : 32; 77 | 78 | // for whitelist/blacklist table 79 | src_ip_hash_val : 12; 80 | dst_ip_hash_val : 12; 81 | bl_src_ip_entry_val : 2; 82 | bl_dst_ip_entry_val : 2; 83 | wl_src_ip_entry_val : 2; 84 | wl_dst_ip_entry_val : 2; 85 | 86 | // for check_no_proxy_table 87 | no_proxy_table_hash_val : 13; 88 | no_proxy_table_entry_val : 2; 89 | 90 | // for check_syn_proxy_table 91 | syn_proxy_table_hash_val : 16; 92 | syn_proxy_table_entry_val : 39; 93 | 94 | // for connection num & packet size detector 95 | hh_hash_val0 : 8;//perhaps be 16 96 | hh_hash_val1 : 8; 97 | hh_size_count_val0 : 32; 98 | hh_size_count_val1 : 32; 99 | hh_conn_count_val0 : 32; 100 | hh_conn_count_val1 : 32; 101 | 102 | } 103 | 104 | } 105 | metadata meta_t meta; 106 | 107 | //********METADATA ENDS******** 108 | 109 | 110 | 111 | //********REGISTERS******** 112 | //********11 * 8192 byte = 88KB in total******** 113 | register whitelist_table { 114 | width : 2; 115 | instance_count : 4096; 116 | } 117 | register blacklist_table { 118 | width : 2; 119 | instance_count : 4096; 120 | } 121 | register no_proxy_table { 122 | width : 2; 123 | instance_count : NO_PROXY_TABLE_SIZE; 124 | } 125 | register syn_proxy_table { 126 | /* 127 | |32 bits offset|6 bits port(server port)|1 bit is_valid| 128 | */ 129 | width : 39; // 32 bit offset + 6 bit port + 1 bit is_valid 130 | instance_count : SYN_PROXY_TABLE_SIZE; 131 | } 132 | register hh_size_hashtable0 133 | { 134 | width: 32; 135 | instance_count: 256; 136 | } 137 | register hh_size_hashtable1 138 | { 139 | width : 32; 140 | instance_count:256; 141 | } 142 | register hh_conn_hashtable0 143 | { 144 | width: 32; 145 | instance_count: 256; 146 | } 147 | register hh_conn_hashtable1 148 | { 149 | width : 32; 150 | instance_count:256; 151 | } 152 | counter syn_counter { 153 | type : packets; 154 | // static : reply_sa_table; 155 | static : syn_meter_table; 156 | instance_count : 1; 157 | } 158 | counter valid_ack_counter { 159 | type : packets; 160 | static : confirm_connection_table; 161 | instance_count : 1; 162 | } 163 | //********REGISTERS ENDS******** 164 | 165 | 166 | 167 | 168 | action _no_op(){ 169 | no_op(); 170 | } 171 | 172 | action _drop() { 173 | modify_field(meta.to_drop, TRUE); 174 | modify_field(ipv4.dst_addr, 0); 175 | drop(); 176 | } 177 | 178 | 179 | //********for syn_meter_table******** 180 | 181 | 182 | meter syn_meter { 183 | type : packets; 184 | instance_count : 1; 185 | } 186 | action syn_meter_action() { 187 | // read syn proxy status into metadata 188 | execute_meter(syn_meter, 0, meta.syn_proxy_status); 189 | 190 | // count: syn packet 191 | count(syn_counter, 0); 192 | } 193 | table syn_meter_table { 194 | actions { 195 | syn_meter_action; 196 | } 197 | } 198 | 199 | 200 | //********for check_whitelist_table******** 201 | 202 | 203 | action read_whitelist_entry_value() { 204 | modify_field_with_hash_based_offset(meta.src_ip_hash_val, 0, src_ip_hash, 4096); 205 | register_read(meta.wl_src_ip_entry_val, whitelist_table, meta.src_ip_hash_val); 206 | modify_field_with_hash_based_offset(meta.dst_ip_hash_val, 0, dst_ip_hash, 4096); 207 | register_read(meta.wl_dst_ip_entry_val, whitelist_table, meta.dst_ip_hash_val); 208 | } 209 | table check_whitelist_table { 210 | actions { 211 | read_whitelist_entry_value; 212 | } 213 | } 214 | 215 | 216 | //********for check_blacklist_table******** 217 | 218 | 219 | action read_blacklist_entry_value() { 220 | modify_field_with_hash_based_offset(meta.src_ip_hash_val, 0, src_ip_hash, 4096); 221 | register_read(meta.bl_src_ip_entry_val, whitelist_table, meta.src_ip_hash_val); 222 | modify_field_with_hash_based_offset(meta.dst_ip_hash_val, 0, dst_ip_hash, 4096); 223 | register_read(meta.bl_dst_ip_entry_val, whitelist_table, meta.dst_ip_hash_val); 224 | } 225 | table check_blacklist_table { 226 | actions { 227 | read_blacklist_entry_value; 228 | } 229 | } 230 | 231 | 232 | //********for mark_in_blacklist_table******** 233 | 234 | 235 | action mark_in_blacklist() { 236 | modify_field(meta.in_black_list, TRUE); 237 | } 238 | table mark_in_blacklist_table { 239 | actions { 240 | mark_in_blacklist; 241 | } 242 | } 243 | 244 | 245 | 246 | //********for check_no_proxy_table******** 247 | 248 | 249 | action read_no_proxy_table_entry_value() { 250 | modify_field_with_hash_based_offset(meta.no_proxy_table_hash_val, 0, tcp_five_tuple_hash, NO_PROXY_TABLE_SIZE); 251 | register_read(meta.no_proxy_table_entry_val, no_proxy_table, meta.no_proxy_table_hash_val); 252 | } 253 | table check_no_proxy_table { 254 | actions { 255 | read_no_proxy_table_entry_value; 256 | } 257 | } 258 | 259 | 260 | //********for sub_delta_to_seq_table******** 261 | 262 | 263 | action sub_delta_to_seq() { 264 | modify_field(meta.to_drop, FALSE); 265 | subtract_from_field(tcp.seq_no, (meta.syn_proxy_table_entry_val >> 7) & 0xffffffff); 266 | } 267 | table sub_delta_to_seq_table { 268 | actions { 269 | sub_delta_to_seq; 270 | } 271 | } 272 | 273 | 274 | //********for add_delta_to_ack_table******** 275 | 276 | 277 | action add_delta_to_ack() { 278 | modify_field(meta.to_drop, FALSE); 279 | add_to_field(tcp.ack_no, (meta.syn_proxy_table_entry_val >> 7) & 0xffffffff); 280 | } 281 | table add_delta_to_ack_table { 282 | actions { 283 | add_delta_to_ack; 284 | } 285 | } 286 | 287 | 288 | //********for check_syn_proxy_table******** 289 | 290 | 291 | action read_syn_proxy_table_entry_value() { 292 | modify_field_with_hash_based_offset(meta.syn_proxy_table_hash_val, 0, tcp_five_tuple_hash, SYN_PROXY_TABLE_SIZE); 293 | register_read(meta.syn_proxy_table_entry_val, syn_proxy_table, meta.syn_proxy_table_hash_val); 294 | } 295 | table check_syn_proxy_table { 296 | actions { 297 | read_syn_proxy_table_entry_value; 298 | } 299 | } 300 | 301 | 302 | //********for calculate_syn_cookie_table******** 303 | 304 | 305 | // use a simpler version of syn-cookie 306 | // timestamp(for connection timeout), MSS(for ack packet reconstruction) not implemented 307 | action calculate_syn_cookie_from_client(key1, key2){ 308 | modify_field(meta.cookie_key1, key1); 309 | modify_field(meta.cookie_key2, key2); 310 | modify_field_with_hash_based_offset(meta.cookie_val1, 0, syn_cookie_key1_calculation, 65536);/*could be larger*/ 311 | modify_field_with_hash_based_offset(meta.cookie_val2, 0, syn_cookie_key2_calculation, 65536);/*could be larger*/ 312 | } 313 | action calculate_syn_cookie_from_server(key1, key2){ 314 | modify_field(meta.cookie_key1, key1); 315 | modify_field(meta.cookie_key2, key2); 316 | modify_field_with_hash_based_offset(meta.cookie_val1, 0, syn_cookie_key1_reverse_calculation, 65536);/*could be larger*/ 317 | modify_field_with_hash_based_offset(meta.cookie_val2, 0, syn_cookie_key2_reverse_calculation, 65536);/*could be larger*/ 318 | } 319 | table calculate_syn_cookie_table { 320 | reads { 321 | // for syn & ack, it is definitely from client 322 | // syn+ack comes from server 323 | tcp.flags : ternary; 324 | } 325 | actions { 326 | _drop; 327 | calculate_syn_cookie_from_client; 328 | calculate_syn_cookie_from_server; 329 | } 330 | } 331 | 332 | 333 | //********for check_proxy_status_table******** 334 | 335 | 336 | action turn_on_proxy() { 337 | modify_field(meta.syn_proxy_status, PROXY_ON); 338 | 339 | } 340 | action turn_off_proxy() { 341 | modify_field(meta.syn_proxy_status, PROXY_OFF); 342 | } 343 | table check_proxy_status_table { 344 | actions { 345 | turn_on_proxy; 346 | turn_off_proxy; 347 | } 348 | } 349 | 350 | 351 | //********for drop_table******** 352 | 353 | 354 | table drop_table { 355 | actions { 356 | _drop; 357 | } 358 | } 359 | 360 | //********for empty_conn_in_proxy_table_table******** 361 | 362 | 363 | action empty_conn_in_proxy_table() { 364 | modify_field(meta.to_drop, FALSE); 365 | // subtract delta to seq# 366 | subtract_from_field(tcp.seq_no, meta.syn_proxy_table_entry_val >> 7); 367 | // empty the corresponding entry in syn_proxy_table 368 | register_write(syn_proxy_table, meta.syn_proxy_table_hash_val, 0); 369 | } 370 | table empty_conn_in_proxy_table_table { 371 | actions { 372 | empty_conn_in_proxy_table; 373 | } 374 | } 375 | 376 | //********for open_window_table******** 377 | 378 | 379 | action open_window() { 380 | modify_field(meta.to_drop, FALSE); 381 | // set tcp seq# to syn cookie value 382 | modify_field(meta.seq_no_offset, (meta.syn_proxy_table_entry_val & 0x7fffffff80) >> 7); 383 | // set seq_no_offset 384 | // TODO: by default, we reckon tcp.seq_no > cookie_val 385 | subtract(meta.seq_no_offset, tcp.seq_no, meta.seq_no_offset); 386 | modify_field(tcp.seq_no, ((meta.syn_proxy_table_entry_val & 0x7fffffff80) >> 7) + 1); 387 | // write offset, port, is_Valid into syn_proxy_table 388 | register_write(syn_proxy_table, meta.syn_proxy_table_hash_val, (meta.seq_no_offset << 7) | (standard_metadata.ingress_port << 1) | 0x1); 389 | 390 | modify_field(tcp.flags, TCP_FLAG_ACK); 391 | 392 | // modify_field(ipv4.identification, standard_metadata.ingress_port); 393 | /*********************************************/ 394 | } 395 | table open_window_table { 396 | actions { 397 | open_window; 398 | } 399 | } 400 | 401 | 402 | //********for reply_sa_table******** 403 | 404 | 405 | action reply_sa() { 406 | modify_field(meta.to_drop, FALSE); 407 | 408 | // empty the entry in proxy table 409 | register_write(syn_proxy_table, meta.syn_proxy_table_hash_val, 0); 410 | // reply client with syn+ack and a certain seq no, and window size 0 411 | 412 | // no need to exchange ethernet values 413 | // since forward table will do this for us 414 | // // exchange src-eth, dst-eth 415 | // modify_field(ethernet.src_addr, meta.eth_da); 416 | // modify_field(ethernet.dst_addr, meta.eth_sa); 417 | // exchange src-ip, dst-ip 418 | modify_field(ipv4.src_addr, meta.ipv4_da); 419 | modify_field(ipv4.dst_addr, meta.ipv4_sa); 420 | // exchange src-port, dst-port 421 | modify_field(tcp.srcPort, meta.tcp_dp); 422 | modify_field(tcp.dstPort, meta.tcp_sp); 423 | // set tcp flags: SYN+ACK 424 | modify_field(tcp.flags, TCP_FLAG_ACK | TCP_FLAG_SYN); 425 | // set ack# to be seq# + 1 426 | modify_field(tcp.ack_no, tcp.seq_no + 1); 427 | // set seq# to be a hash val 428 | modify_field(tcp.seq_no, meta.cookie_val1); 429 | // set window to be 0. 430 | // stop client from transferring data 431 | modify_field(tcp.window, 0); 432 | // modify_field(ipv4.identification, standard_metadata.ingress_port); 433 | // count: syn packet 434 | // count(syn_counter, 0); 435 | } 436 | table reply_sa_table { 437 | actions { 438 | reply_sa; 439 | } 440 | } 441 | 442 | 443 | //********for confirm_connection_table******** 444 | 445 | 446 | action confirm_connection() { 447 | // handshake with client finished, start establishing connection with server 448 | modify_field(meta.to_drop, FALSE); 449 | // syn_proxy_table : set seq# 450 | register_write(syn_proxy_table, meta.syn_proxy_table_hash_val, ((tcp.ack_no - 1) << 7) | CONFIRMED_CONNECTION_MARK); 451 | // set seq# to be seq# - 1 (same as the beginning syn packet seq#) 452 | modify_field(tcp.seq_no, tcp.seq_no - 1); 453 | // set flag: syn 454 | modify_field(tcp.flags, TCP_FLAG_SYN); 455 | // set ack# 0 (optional) 456 | modify_field(tcp.ack_no, 0); 457 | 458 | 459 | // count: valid ack 460 | count(valid_ack_counter, 0); 461 | } 462 | table confirm_connection_table { 463 | actions { 464 | confirm_connection; 465 | } 466 | } 467 | 468 | //********for mark_forward_normally_table******** 469 | action mark_forward_normally() { 470 | modify_field(meta.to_drop, FALSE); 471 | } 472 | table mark_forward_normally_table { 473 | actions { 474 | mark_forward_normally; 475 | } 476 | } 477 | 478 | //********for mark_no_proxy_table******** 479 | action mark_no_conn() { 480 | modify_field(meta.to_drop, FALSE); 481 | register_write(no_proxy_table, meta.no_proxy_table_hash_val, CONN_NOT_EXIST); 482 | } 483 | action mark_no_conn_could_drop() { 484 | register_write(no_proxy_table, meta.no_proxy_table_hash_val, CONN_NOT_EXIST); 485 | } 486 | table mark_no_conn_table { 487 | actions { 488 | mark_no_conn_could_drop; 489 | } 490 | } 491 | action mark_has_syn() { 492 | modify_field(meta.to_drop, FALSE); 493 | register_write(no_proxy_table, meta.no_proxy_table_hash_val, CONN_HAS_SYN); 494 | } 495 | action mark_has_ack() { 496 | modify_field(meta.to_drop, FALSE); 497 | register_write(no_proxy_table, meta.no_proxy_table_hash_val, CONN_HAS_ACK); 498 | // write into whitelist 499 | register_write(whitelist_table, meta.src_ip_hash_val, 0x2 | meta.wl_src_ip_entry_val); 500 | 501 | } 502 | table mark_no_proxy_table{ 503 | reads{ 504 | meta.no_proxy_table_entry_val : exact; 505 | tcp.flags : ternary; 506 | } 507 | actions{ 508 | _no_op; 509 | mark_forward_normally; 510 | mark_has_ack; 511 | mark_has_syn; 512 | mark_no_conn; 513 | } 514 | } 515 | 516 | 517 | //********for set_size_count_table******** 518 | 519 | 520 | action pkt_size_count() { 521 | modify_field_with_hash_based_offset(meta.hh_hash_val0, 0, heavy_hitter_hash0, 256); 522 | register_read(meta.hh_size_count_val0, hh_size_hashtable0, meta.hh_hash_val0); 523 | add_to_field(meta.hh_size_count_val0, ipv4.totalLen); 524 | register_write(hh_size_hashtable0, meta.hh_hash_val0, meta.hh_size_count_val0); 525 | 526 | modify_field_with_hash_based_offset(meta.hh_hash_val1, 0, heavy_hitter_hash1, 256); 527 | register_read(meta.hh_size_count_val1, hh_size_hashtable1, meta.hh_hash_val1); 528 | add_to_field(meta.hh_size_count_val1, ipv4.totalLen); 529 | register_write(hh_size_hashtable1, meta.hh_hash_val1, meta.hh_size_count_val1); 530 | } 531 | 532 | table set_size_count_table{ 533 | 534 | actions{ 535 | pkt_size_count; 536 | } 537 | } 538 | 539 | 540 | //********for conn_count_inc_table******** 541 | 542 | 543 | action pkt_count_inc() { 544 | register_read(meta.hh_conn_count_val0, hh_conn_hashtable0, meta.hh_hash_val0); 545 | add_to_field(meta.hh_conn_count_val0, 1); 546 | register_write(hh_conn_hashtable0, meta.hh_hash_val0, meta.hh_conn_count_val0); 547 | 548 | register_read(meta.hh_conn_count_val1, hh_conn_hashtable1, meta.hh_hash_val1); 549 | add_to_field(meta.hh_conn_count_val1, 1); 550 | register_write(hh_conn_hashtable1, meta.hh_hash_val1, meta.hh_conn_count_val1); 551 | } 552 | 553 | table conn_count_inc_table{ 554 | actions{ 555 | pkt_count_inc; 556 | } 557 | } 558 | 559 | 560 | //********for conn_count_dec_table******** 561 | 562 | 563 | action pkt_count_dec() { 564 | register_read(meta.hh_conn_count_val0, hh_conn_hashtable0, meta.hh_hash_val0); 565 | subtract_from_field(meta.hh_conn_count_val0, 1); 566 | register_write(hh_conn_hashtable0, meta.hh_hash_val0, meta.hh_conn_count_val0); 567 | 568 | register_read(meta.hh_conn_count_val1, hh_conn_hashtable1, meta.hh_hash_val1); 569 | subtract_from_field(meta.hh_conn_count_val1, 1); 570 | register_write(hh_conn_hashtable1, meta.hh_hash_val1, meta.hh_conn_count_val1); 571 | } 572 | 573 | table conn_count_dec_table{ 574 | actions{ 575 | pkt_count_dec; 576 | } 577 | } 578 | 579 | 580 | //********for add_to_blacklist_table******** 581 | 582 | 583 | action add_to_blacklist() { 584 | register_write(blacklist_table, meta.src_ip_hash_val, 0x2 | meta.bl_src_ip_entry_val); 585 | } 586 | 587 | table add_to_blacklist_table{ 588 | actions{ 589 | add_to_blacklist; 590 | } 591 | } 592 | 593 | 594 | 595 | //********for ipv4_lpm_table******** 596 | 597 | 598 | action set_nhop(nhop_ipv4, port) { 599 | modify_field(meta.nhop_ipv4, nhop_ipv4); 600 | modify_field(standard_metadata.egress_spec, port); 601 | add_to_field(ipv4.ttl, -1); 602 | } 603 | table ipv4_lpm_table { 604 | reads { 605 | ipv4.dst_addr : lpm; 606 | } 607 | actions { 608 | set_nhop; 609 | _drop; 610 | } 611 | size: 1024; 612 | } 613 | 614 | 615 | 616 | 617 | //********for forward_table******** 618 | 619 | 620 | action set_dmac(dmac) { 621 | modify_field(ethernet.dst_addr, dmac); 622 | } 623 | table forward_table { 624 | reads { 625 | meta.nhop_ipv4 : exact; 626 | } 627 | actions { 628 | set_dmac; 629 | _drop; 630 | } 631 | size: 512; 632 | } 633 | 634 | 635 | 636 | 637 | control syn_proxy { 638 | // syn proxy on 639 | // no need for session check since we use stateless SYN-cookie method 640 | 641 | // whether the packet is an ACK, SYN or SYN+ACK 642 | // syn-cookie will be used 643 | // it must be calculated. 644 | // if it is not one of the three types above, it will be dropped in this table 645 | apply(check_syn_proxy_table); 646 | /* entry in syn_proxy_table 647 | |32 bits offset|6 bits port(server port)|1 bit is_valid| 648 | */ 649 | if(meta.syn_proxy_table_entry_val & 0x1 == VALID and tcp.flags != TCP_FLAG_SYN){ 650 | // valid entry in syn_proxy_table 651 | // and it's not a new connection 652 | if(standard_metadata.ingress_port == ((meta.syn_proxy_table_entry_val & 0x7e) >> 1)){ 653 | // extract server port from the entry 654 | 655 | // from server to client 656 | // seq# - delta 657 | if(tcp.flags & (TCP_FLAG_FIN | TCP_FLAG_ACK) == (TCP_FLAG_FIN | TCP_FLAG_ACK)){ 658 | // it's a finishing packet from server 659 | apply(empty_conn_in_proxy_table_table); 660 | }else{ 661 | apply(sub_delta_to_seq_table); 662 | } 663 | }else { 664 | // from client to server 665 | // ack# + delta 666 | apply(add_delta_to_ack_table); 667 | } 668 | }else { 669 | // no record in syn_proxy_table 670 | if((tcp.flags == (TCP_FLAG_SYN | TCP_FLAG_ACK)) and ((meta.syn_proxy_table_entry_val & 0x7f) == CONFIRMED_CONNECTION_MARK)){/*last 7 bits*/ 671 | // syn+ack from server 672 | // this connection has been acked 673 | // open client's window and set record in syn_proxy_table 674 | apply(open_window_table); 675 | } else{ 676 | // calculate syn cookie 677 | apply(calculate_syn_cookie_table); 678 | if(tcp.flags == TCP_FLAG_SYN){ 679 | // SYN packet 680 | // clear the corresponding entry 681 | // and send back syn+ack with syn cookie 682 | apply(reply_sa_table); 683 | } else if(tcp.flags & 0x12 == TCP_FLAG_ACK) { 684 | // has ack but no syn 685 | // make sure ack# is right 686 | if(tcp.ack_no == meta.cookie_val1 + 1 or tcp.ack_no == meta.cookie_val2 + 1){ 687 | // mark the entry as 'has been acked' 688 | // and establish connection with server 689 | apply(confirm_connection_table); 690 | } 691 | } 692 | } 693 | } 694 | } 695 | 696 | control conn_filter { 697 | // writing new logic 698 | // all packets go through the first register array 'no_proxy_table'(2 bits per entry), entries of which are all set to 00 by default 699 | // we're gonna use symmetry hash (hash to the same value for packets of both two directions) 700 | // whatever the entry is, if proxy is on and packet is SYN 701 | // direct it to syn proxy module 702 | // else: 703 | // if the corresponding entry is 00: 704 | // if proxy is off and the incoming packet is SYN, then write 01 into the corresponding entry and forward 705 | // else (proxy is on or incoming packet is not SYN), direct it to syn proxy module 706 | // if the corresponding entry is 01 and the incoming packet is SYN, SYN+ACK or RST, forward normally 707 | // if the corresponding entry is 01 and the incoming packet is ACK, then write 10 into the corresponding entry and forward 708 | // if the corresponding entry is 01 and the incoming packet contains FIN, then write 00 into the corresponding entry and forward 709 | // if the corresponding entry is 10 then forward it normally (or write 00 if the packet contains FIN) 710 | 711 | apply(check_no_proxy_table); 712 | 713 | if((meta.no_proxy_table_entry_val == CONN_NOT_EXIST and meta.syn_proxy_status == PROXY_ON) 714 | or 715 | (meta.no_proxy_table_entry_val == CONN_NOT_EXIST and tcp.flags != TCP_FLAG_SYN) 716 | or 717 | (tcp.flags == TCP_FLAG_SYN and meta.syn_proxy_status == PROXY_ON)){ 718 | apply(mark_no_conn_table); 719 | syn_proxy(); 720 | } 721 | else{ 722 | // replace all logic with a match-action table 723 | // this part rewrite entries in no_proxy_table 724 | /* 725 | if(meta.no_proxy_table_entry_val == CONN_NOT_EXIST){ 726 | // proxy is off and packet is SYN 727 | // write 01 into no_proxy_table 728 | apply(mark_has_syn_table); 729 | }else if(meta.no_proxy_table_entry_val == CONN_HAS_SYN){ 730 | // when proxy is off 731 | // SYN=>mark_forward_normally 732 | // SYN&ACK=>mark_forward_normally 733 | // RST=>mark_forward_normally 734 | // ACK=>mark_has_ack 735 | // ACK&FIN=>mark_no_conn 736 | apply(conn_has_syn_table); 737 | }else if(meta.no_proxy_table_entry_val == CONN_HAS_ACK){ 738 | // ACK&FIN => mark_has_syn 739 | // else => mark_forward_normally 740 | apply(conn_has_ack_table); 741 | } 742 | */ 743 | apply(mark_no_proxy_table); 744 | } 745 | } 746 | control ingress { 747 | 748 | // first count syn packets 749 | if(tcp.flags ^ TCP_FLAG_SYN == 0){ 750 | // only has syn 751 | apply(syn_meter_table); 752 | } 753 | // check if it's in blacklist 754 | apply(check_blacklist_table); 755 | if(meta.bl_src_ip_entry_val != 0 or meta.bl_dst_ip_entry_val != 0){ 756 | apply(mark_in_blacklist_table); 757 | } 758 | if(meta.in_black_list == FALSE){ 759 | // if not in blacklist 760 | // check if it's in whitelist 761 | apply(check_whitelist_table); 762 | if(meta.wl_src_ip_entry_val != 0 or meta.wl_dst_ip_entry_val != 0){ 763 | apply(mark_forward_normally_table); 764 | }else { 765 | // check syn proxy status (on or off) 766 | apply(check_proxy_status_table); 767 | // no_proxy_table and syn proxy 768 | conn_filter(); 769 | } 770 | 771 | // unspoofing module 772 | // packets statistics 773 | if(meta.to_drop == FALSE){ 774 | // packets size count 775 | apply(set_size_count_table); 776 | // connection count (for each src ip) 777 | if(tcp.flags & TCP_FLAG_SYN == TCP_FLAG_SYN){ 778 | print '\n' 779 | time.sleep(listen_interval) 780 | 781 | if __name__ == '__main__': 782 | main() 783 | 784 | // add 1 to count-min sketch 785 | apply(conn_count_inc_table); 786 | } else if(tcp.flags & TCP_FLAG_FIN == TCP_FLAG_FIN){ 787 | // subtract 1 from count-min sketch 788 | apply(conn_count_dec_table); 789 | } 790 | // TODO: bug. Could add server addr to blacklist 791 | if((meta.hh_size_count_val0 > HH_SIZE_THRESHOLD and 792 | meta.hh_size_count_val1 > HH_SIZE_THRESHOLD) 793 | or 794 | (meta.hh_conn_count_val0 > HH_CONN_THRESHOLD and 795 | meta.hh_conn_count_val1 > HH_CONN_THRESHOLD)){ 796 | apply(add_to_blacklist_table); 797 | } 798 | }else{ 799 | apply(drop_table); 800 | } 801 | 802 | apply(ipv4_lpm_table); 803 | apply(forward_table); 804 | } 805 | } 806 | 807 | 808 | 809 | //********for send_frame******** 810 | 811 | 812 | action rewrite_mac(smac) { 813 | modify_field(ethernet.src_addr, smac); 814 | } 815 | table send_frame { 816 | reads { 817 | standard_metadata.egress_port: exact; 818 | } 819 | actions { 820 | rewrite_mac; 821 | _drop; 822 | } 823 | size: 256; 824 | } 825 | 826 | 827 | 828 | control egress { 829 | if(standard_metadata.instance_type == 0){ 830 | // not cloned 831 | apply(send_frame); 832 | } 833 | } 834 | 835 | -------------------------------------------------------------------------------- /DoS/bmv2/run_demo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2013-present Barefoot Networks, Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 18 | 19 | source $THIS_DIR/../../../env.sh 20 | 21 | P4C_BM_SCRIPT=$P4C_BM_PATH/p4c_bm/__main__.py 22 | 23 | SWITCH_PATH=$BMV2_PATH/targets/simple_switch/simple_switch 24 | CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI 25 | # CLI_PATH=$BMV2_PATH/tools/runtime_CLI.py 26 | 27 | # create CPU port 28 | intf0="cpu-veth-0" 29 | intf1="cpu-veth-1" 30 | if ! ip link show $intf0 &> /dev/null; then 31 | ip link add name $intf0 type veth peer name $intf1 32 | ip link set dev $intf0 up 33 | ip link set dev $intf1 up 34 | TOE_OPTIONS="rx tx sg tso ufo gso gro lro rxvlan txvlan rxhash" 35 | for TOE_OPTION in $TOE_OPTIONS; do 36 | /sbin/ethtool --offload $intf0 "$TOE_OPTION" off 37 | /sbin/ethtool --offload $intf1 "$TOE_OPTION" off 38 | done 39 | fi 40 | sysctl net.ipv6.conf.$intf0.disable_ipv6=1 41 | sysctl net.ipv6.conf.$intf1.disable_ipv6=1 42 | 43 | TARGET=syntry 44 | TARGET_SRC=$TARGET.p4 45 | TARGET_JSON=$TARGET.json 46 | 47 | $P4C_BM_SCRIPT p4src/$TARGET_SRC --json $TARGET_JSON 48 | # This gives libtool the opportunity to "warm-up" 49 | sudo $SWITCH_PATH >/dev/null 2>&1 50 | sudo PYTHONPATH=$PYTHONPATH:$BMV2_PATH/mininet/ python topo.py \ 51 | --behavioral-exe $SWITCH_PATH \ 52 | --json $TARGET_JSON \ 53 | --cli $CLI_PATH \ 54 | --thrift-port 22222 55 | -------------------------------------------------------------------------------- /DoS/bmv2/run_switch.py: -------------------------------------------------------------------------------- 1 | # This python file aims to keep update of some of the flow table in the switch 2 | # including syn cookie hash key (timely update) 3 | # and check for the value of syn meter, syn counter, valid ack counter from time to time 4 | 5 | import scapy.all 6 | import subprocess 7 | import os 8 | import re 9 | import time 10 | 11 | syn_meter_name = 'syn_meter' 12 | syn_counter_name = 'syn_counter' 13 | vack_counter_name = 'valid_ack_counter' 14 | proxy_status_table_name = 'check_proxy_status_table' 15 | proxy_on_action_name = 'turn_on_proxy' 16 | proxy_off_action_name = 'turn_off_proxy' 17 | blacklist_register_name = 'blacklist_table' 18 | whitelist_register_name = 'whitelist_table' 19 | proxy_status = -1 20 | 21 | def send_to_CLI(cmd): 22 | this_dir = os.path.dirname(os.path.realpath(__file__)) 23 | p = subprocess.Popen(os.path.join(this_dir, 'sswitch_CLI.sh'), stdout=subprocess.PIPE, stdin=subprocess.PIPE) 24 | output = p.communicate(input=cmd)[0] 25 | # print output 26 | return output 27 | 28 | def register_read(register_name, index): 29 | return send_to_CLI('register_read ' + register_name + ' ' + str(index)) 30 | 31 | def register_write(register_name, index, value): 32 | return send_to_CLI('register_write ' + register_name + ' ' + str(index) + ' ' + str(value)) 33 | 34 | def meter_get_rates(meter_name, index): 35 | return send_to_CLI('meter_get_rates ' + meter_name + ' ' + str(index)) 36 | 37 | def counter_read(counter_name, index): 38 | return send_to_CLI('counter_read ' + counter_name + ' ' + str(index)) 39 | 40 | def table_reset_default(table_name): 41 | return send_to_CLI('table_reset_default ' + table_name) 42 | 43 | def table_set_default(table_name, default_action_name): 44 | return send_to_CLI('table_set_default ' + table_name + ' ' + default_action_name) 45 | 46 | def read_meter(): 47 | global syn_meter_name 48 | # print 'Reading syn_meter data...' 49 | meter_get_rates(syn_meter_name , 0) 50 | return 0 51 | 52 | def read_counters(): 53 | global syn_counter_name 54 | global vack_counter_name 55 | # print 'Reading syn_counter and valid_ack_counter data...' 56 | 57 | counter_results = {} 58 | 59 | syn_counter_result = counter_read(syn_counter_name, 0) 60 | vack_counter_result = counter_read(vack_counter_name, 0) 61 | pattern = re.compile(r'BmCounterValue\(packets=(\d+), bytes=(\d+)\)') 62 | syn_match = pattern.search(syn_counter_result) 63 | if(syn_match): 64 | counter_results['syn'] = (int(syn_match.group(1)), int(syn_match.group(2))) 65 | vack_match = pattern.search(vack_counter_result) 66 | if(vack_match): 67 | counter_results['vack'] = (int(vack_match.group(1)), int(vack_match.group(2))) 68 | return counter_results 69 | 70 | def turn_on_proxy(): 71 | global proxy_status 72 | if proxy_status == 1: 73 | return 74 | print 'Turning on proxy...' 75 | print table_set_default(proxy_status_table_name, proxy_on_action_name) 76 | proxy_status = 1 77 | 78 | def turn_off_proxy(): 79 | global proxy_status 80 | if proxy_status == 0: 81 | return 82 | print 'Turning off proxy...' 83 | print table_set_default(proxy_status_table_name, proxy_off_action_name) 84 | proxy_status = 0 85 | 86 | def check_syn_and_ack_number(listen_interval, last_counter_val, syn_packets_speed_threshold=500): 87 | print 'last_counter_val:', last_counter_val 88 | # meter_result = read_meter() 89 | counter_results = read_counters() 90 | print 'counter_results:', counter_results 91 | if last_counter_val[0] == -1 and last_counter_val[1] == -1: 92 | # do not calculate spped 93 | return [counter_results['syn'][0], counter_results['vack'][0]] 94 | # syn speed 95 | syn_speed = float((counter_results['syn'][0] - last_counter_val[0]) / listen_interval) 96 | if syn_speed > syn_packets_speed_threshold: 97 | print 'Syn Proxy On. \tSpeed of syn packets is %d.' % syn_speed 98 | turn_on_proxy() 99 | # number of syn & valid ack packets 100 | print 'proxy_status:', proxy_status 101 | if proxy_status != 0: 102 | syn_increase = counter_results['syn'][0] - last_counter_val[0] 103 | vack_increase = counter_results['vack'][0] - last_counter_val[1] 104 | print 'syn_increase:', syn_increase, 'vack_increase:', vack_increase 105 | if abs(syn_increase - vack_increase) < min(syn_increase, vack_increase) * 1 / 8.0: 106 | print 'Syn Proxy Off. \tDifferece between syn and valid ack packets during the last period is %d.' % abs(syn_increase - vack_increase) 107 | turn_off_proxy() 108 | 109 | return [counter_results['syn'][0], counter_results['vack'][0]] 110 | 111 | def update_black_list(rows=4096): 112 | blacklist_result = [0] * rows 113 | for i in range(0, rows): 114 | register_result = register_read(blacklist_register_name, i) 115 | pattern = re.compile(blacklist_register_name + r'\[\d+\]=\s*(\d+)') 116 | match = pattern.search(register_result) 117 | if(match): 118 | blacklist_result[i] = match.group(1) 119 | if blacklist_result[i] >= 2: # 10 or 11 120 | register_write(blacklist_register_name, i, 1) 121 | else: 122 | register_write(blacklist_register_name, i, 0) 123 | 124 | def update_white_list(rows=4096): 125 | whitelist_result = [0] * rows 126 | for i in range(0, rows): 127 | register_result = register_read(whitelist_register_name, i) 128 | pattern = re.compile(whitelist_register_name + r'\[\d+\]=\s*(\d+)') 129 | match = pattern.search(register_result) 130 | if(match): 131 | whitelist_result[i] = match.group(1) 132 | if whitelist_result[i] >= 2: # 10 or 11 133 | register_write(whitelist_register_name, i, 1) 134 | else: 135 | register_write(whitelist_register_name, i, 0) 136 | def main(): 137 | global proxy_status 138 | listen_interval = 0.1 139 | last_counter_val = [-1, -1] 140 | while True: 141 | last_counter_val = check_syn_and_ack_number(listen_interval, last_counter_val) 142 | # it takes about 2.5 sec to check 10 entries...... 143 | # update_black_list(10) 144 | # update_white_list(10) 145 | print '\n' 146 | time.sleep(listen_interval) 147 | 148 | 149 | if __name__ == '__main__': 150 | main() 151 | 152 | -------------------------------------------------------------------------------- /DoS/bmv2/sswitch_CLI.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 4 | 5 | source $THIS_DIR/../../../env.sh 6 | 7 | 8 | # CLI_PATH=$BMV2_PATH/tools/runtime_CLI.py 9 | CLI_PATH=$BMV2_PATH/targets/simple_switch/sswitch_CLI 10 | 11 | $CLI_PATH simple_nat.json 22222 12 | -------------------------------------------------------------------------------- /DoS/bmv2/topo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Copyright 2013-present Barefoot Networks, Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | from mininet.net import Mininet 18 | from mininet.topo import Topo 19 | from mininet.log import setLogLevel, info 20 | from mininet.cli import CLI 21 | from mininet.link import TCLink, Intf 22 | 23 | from p4_mininet import P4Switch, P4Host 24 | 25 | import argparse 26 | from time import sleep 27 | import os 28 | import subprocess 29 | 30 | _THIS_DIR = os.path.dirname(os.path.realpath(__file__)) 31 | _THRIFT_BASE_PORT = 22222 32 | 33 | parser = argparse.ArgumentParser(description='Mininet demo') 34 | parser.add_argument('--behavioral-exe', help='Path to behavioral executable', 35 | type=str, action="store", required=True) 36 | parser.add_argument('--json', help='Path to JSON config file', 37 | type=str, action="store", required=True) 38 | parser.add_argument('--cli', help='Path to BM CLI', 39 | type=str, action="store", required=True) 40 | parser.add_argument('--thrift-port', help='Thrift server port for table updates', 41 | type=int, action="store", required=True) 42 | 43 | 44 | args = parser.parse_args() 45 | 46 | class MyTopo(Topo): 47 | def __init__(self, sw_path, json_path, thrift_port, **opts): 48 | Topo.__init__(self,**opts) 49 | 50 | switch = self.addSwitch('s1', 51 | sw_path = sw_path, 52 | json_path = json_path, 53 | thrift_port = thrift_port, 54 | pcap_dump = True) 55 | #internal host 56 | h1 = self.addHost('h1', 57 | ip = "10.0.0.10", 58 | mac = "00:00:00:00:00:10") 59 | self.addLink(h1,switch) 60 | #external host 61 | h2 = self.addHost('h2', 62 | ip = "11.0.0.10", 63 | mac = "00:00:00:00:00:20") 64 | self.addLink(h2, switch) 65 | 66 | 67 | def main(): 68 | 69 | topo = MyTopo(args.behavioral_exe, 70 | args.json, 71 | args.thrift_port) 72 | 73 | 74 | net = Mininet(topo = topo, 75 | host = P4Host, 76 | switch = P4Switch, 77 | controller = None ) 78 | 79 | 80 | cpu_intf = Intf("cpu-veth-1", net.get('s1'), 11) 81 | 82 | 83 | net.start() 84 | 85 | 86 | sw_macs = ["00:00:00:00:00:01", "00:00:00:00:00:02"] 87 | 88 | sw_addrs = ["10.0.0.1", "11.0.0.1"] 89 | 90 | # h_macs = ["00:05:00:00:00:10","00:04:00:00:00:10"] 91 | # h_addrs = ['10.0.0.20','10.0.0.10'] 92 | 93 | for n in xrange(2): 94 | h = net.get('h%d' %(n + 1)) 95 | h.setARP(sw_addrs[n], sw_macs[n]) 96 | h.setDefaultRoute("dev eth0 via %s" % sw_addrs[n]) 97 | 98 | for n in xrange(2): 99 | h = net.get('h%d' % (n + 1)) 100 | h.describe() 101 | 102 | sleep(1) 103 | 104 | cmd = [args.cli, args.json, str(args.thrift_port)] 105 | with open("commands.txt", "r") as f: 106 | print " ".join(cmd) 107 | try: 108 | output = subprocess.check_output(cmd, stdin = f) 109 | print output 110 | except subprocess.CalledProcessError as e: 111 | print e 112 | print e.output 113 | 114 | 115 | sleep(1) 116 | 117 | 118 | print "Ready !" 119 | 120 | CLI( net ) 121 | net.stop() 122 | 123 | if __name__ == '__main__': 124 | setLogLevel( 'info' ) 125 | main() 126 | -------------------------------------------------------------------------------- /DoS/bmv2/topo.txt: -------------------------------------------------------------------------------- 1 | switches 1 2 | hosts 2 3 | h1 s1 4 | h2 s1 5 | -------------------------------------------------------------------------------- /DoS/tofino/README.md: -------------------------------------------------------------------------------- 1 | # DoS SYN proxy demo 2 | 3 | ./qy_build.sh compile script 4 | 5 | syntry.p4 the major version 6 | syntry3.p4 simplified version, for testing 7 | 8 | test.py controller, initializing and installing table entries 9 | -------------------------------------------------------------------------------- /DoS/tofino/qy_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #2018.3 qiaoyi 3 | #modified from wsh's script 4 | #build synproxy program 5 | 6 | cd $SDE/pkgsrc/p4-build-4.1.1.15 7 | make clean 8 | echo 'clean done!' 9 | ./configure --prefix=$SDE_INSTALL --with-tofino enable_thrift=yes P4_PATH=$SDE/synproxy/p4research/DoS/tofino/syntry.p4 P4_NAME=synproxy 10 | 11 | make -j4 12 | echo 'make done!' 13 | make install 14 | echo 'make install done!' 15 | sed -e "s/TOFINO_SINGLE_DEVICE/synproxy/" $SDE/pkgsrc/p4-examples-4.1.1.15/tofino_single_device.conf.in > $SDE_INSTALL/share/p4/targets/synproxy.conf 16 | echo 'conf done!' 17 | -------------------------------------------------------------------------------- /DoS/tofino/syntry.p4: -------------------------------------------------------------------------------- 1 | #include "tofino/stateful_alu_blackbox.p4" 2 | #include "tofino/intrinsic_metadata.p4" 3 | 4 | header_type ethernet_t { 5 | fields { 6 | dstAddr : 48; 7 | srcAddr : 48; 8 | etherType : 16; 9 | } 10 | } 11 | 12 | header_type ipv4_t { 13 | fields { 14 | version : 4; 15 | ihl : 4; 16 | diffserv : 8; 17 | totalLen : 16; 18 | identification : 16; 19 | flags : 3; 20 | fragOffset : 13; 21 | ttl : 8; 22 | protocol : 8; 23 | hdrChecksum : 16; 24 | srcAddr : 32; 25 | dstAddr: 32; 26 | } 27 | } 28 | parser start { 29 | //TOFINO: In tofino, the ingress_port meta_data is generated after parser, so nothing is done here. 30 | return parse_ethernet; 31 | 32 | } 33 | 34 | #define ETHERTYPE_IPV4 0x0800 35 | 36 | header ethernet_t ethernet; 37 | 38 | parser parse_ethernet { 39 | extract(ethernet); 40 | set_metadata(meta.eth_da,ethernet.dstAddr); 41 | set_metadata(meta.eth_sa,ethernet.srcAddr); 42 | return select(latest.etherType) { 43 | ETHERTYPE_IPV4 : parse_ipv4; 44 | default: ingress; 45 | } 46 | } 47 | 48 | header ipv4_t ipv4; 49 | 50 | field_list ipv4_checksum_list { 51 | ipv4.version; 52 | ipv4.ihl; 53 | ipv4.diffserv; 54 | ipv4.totalLen; 55 | ipv4.identification; 56 | ipv4.flags; 57 | ipv4.fragOffset; 58 | ipv4.ttl; 59 | ipv4.protocol; 60 | ipv4.srcAddr; 61 | ipv4.dstAddr; 62 | } 63 | field_list_calculation ipv4_checksum { 64 | input { 65 | ipv4_checksum_list; 66 | } 67 | algorithm : csum16; 68 | output_width : 16; 69 | } 70 | 71 | calculated_field ipv4.hdrChecksum { 72 | verify ipv4_checksum; 73 | update ipv4_checksum; 74 | } 75 | 76 | #define IP_PROT_TCP 0x06 77 | 78 | parser parse_ipv4 { 79 | extract(ipv4); 80 | 81 | set_metadata(meta.ipv4_sa, ipv4.srcAddr); 82 | set_metadata(meta.ipv4_da, ipv4.dstAddr); 83 | //TOFINO: We cannot do calculations in parser 84 | //set_metadata(meta.tcpLength, ipv4.totalLen - 20); 85 | return select(ipv4.protocol) { 86 | IP_PROT_TCP : parse_tcp; 87 | default: ingress; 88 | } 89 | 90 | } 91 | 92 | header_type tcp_t { 93 | fields { 94 | srcPort : 16; 95 | dstPort : 16; 96 | seqNo : 32; 97 | ackNo : 32; 98 | dataOffset : 4; 99 | res : 4; 100 | flags : 3; 101 | ack: 1; 102 | psh: 1; 103 | rst: 1; 104 | syn: 1; 105 | fin: 1; 106 | window : 16; 107 | checksum : 16; 108 | urgentPtr : 16; 109 | } 110 | } 111 | 112 | 113 | header tcp_t tcp; 114 | 115 | parser parse_tcp { 116 | extract(tcp); 117 | set_metadata(meta.tcp_sp, tcp.srcPort); 118 | set_metadata(meta.tcp_dp, tcp.dstPort); 119 | set_metadata(meta.tcp_ack, tcp.ack); 120 | set_metadata(meta.tcp_psh, tcp.psh); 121 | set_metadata(meta.tcp_rst, tcp.rst); 122 | set_metadata(meta.tcp_syn, tcp.syn); 123 | set_metadata(meta.tcp_fin, tcp.fin); 124 | set_metadata(meta.tcp_seqNo, tcp.seqNo); 125 | set_metadata(meta.tcp_ackNo, tcp.ackNo); 126 | return ingress; 127 | } 128 | field_list tcp_checksum_list { 129 | ipv4.srcAddr; 130 | ipv4.dstAddr; 131 | 8'0; 132 | ipv4.protocol; 133 | meta.tcpLength; 134 | tcp.srcPort; 135 | tcp.dstPort; 136 | tcp.seqNo; 137 | tcp.ackNo; 138 | tcp.dataOffset; 139 | tcp.res; 140 | tcp.flags; 141 | tcp.ack; 142 | tcp.psh; 143 | tcp.rst; 144 | tcp.syn; 145 | tcp.fin; 146 | tcp.window; 147 | tcp.urgentPtr; 148 | payload; 149 | } 150 | 151 | field_list_calculation tcp_checksum { 152 | input { 153 | tcp_checksum_list; 154 | } 155 | algorithm : csum16; 156 | output_width : 16; 157 | } 158 | /* 159 | calculated_field tcp.checksum { 160 | //TOFINO: We cannot add if here on tofino. 161 | update tcp_checksum; 162 | } 163 | */ 164 | 165 | header_type meta_t { 166 | fields { 167 | eth_sa:48; 168 | eth_da:48; 169 | ipv4_sa : 32; 170 | ipv4_da : 32; 171 | tcp_sp : 16; 172 | tcp_dp : 16; 173 | nhop_ipv4 : 32; 174 | if_ipv4_addr : 32; 175 | if_mac_addr : 48; 176 | is_ext_if : 1; 177 | tcpLength : 16; 178 | in_port : 8; 179 | out_port:8; 180 | 181 | tcp_syn:1; 182 | tcp_ack:1; 183 | reply_type:4;//0 drop 1 syn/ack back to h1 02 syn to h2 03 send h2 ack 04 resubmit 05 forward the packet as normal 184 | tcp_synack:1; 185 | tcp_psh:1; 186 | tcp_rst:1; 187 | tcp_fin:1; 188 | tcp_seqNo:32; 189 | tcp_h1seq:32; 190 | tcp_seqOffset:32; 191 | tcp_ackNo:32; 192 | tcp_h2seq:32; 193 | tcp_ackOffset:32; 194 | 195 | tcp_session_map_index : 8; 196 | reverse_tcp_session_map_index : 8; 197 | dstip_pktcount_map_index: 8; 198 | tcp_session_id : 16; 199 | 200 | dstip_pktcount:32;// how many packets have been sent to this dst IP address 201 | 202 | 203 | tcp_session_is_SYN: 8;// this session has sent a syn to switch 204 | tcp_session_is_ACK: 8;// this session has sent a ack to switchi 205 | tcp_session_h2_reply_sa:8;// h2 in this session has sent a sa to switch 206 | h1_seq : 32; 207 | 208 | } 209 | 210 | } 211 | 212 | metadata meta_t meta; 213 | 214 | field_list l3_hash_fields { 215 | 216 | ipv4.srcAddr; 217 | ipv4.dstAddr; 218 | ipv4.protocol; 219 | tcp.srcPort; 220 | 221 | tcp.dstPort; 222 | } 223 | //get the hash according to the 5-touple of this packet 224 | field_list_calculation tcp_session_map_hash { 225 | input { 226 | l3_hash_fields; 227 | } 228 | algorithm: crc16; 229 | output_width: 8; 230 | 231 | } 232 | 233 | 234 | field_list reverse_l3_hash_fields { 235 | 236 | ipv4.dstAddr; 237 | ipv4.srcAddr; 238 | ipv4.protocol; 239 | 240 | tcp.dstPort; 241 | tcp.srcPort; 242 | 243 | 244 | } 245 | //reverse the src address and dst address, src port and dst port, to get the hash of the reply-packet of this packet 246 | //for example: h1 has a session with h2, according the reverse-hash of packet from h2, we can get the hash of packet from h1. 247 | field_list_calculation reverse_tcp_session_map_hash{ 248 | input { 249 | reverse_l3_hash_fields; 250 | } 251 | algorithm:crc16; 252 | output_width:8; 253 | 254 | } 255 | 256 | 257 | field_list dstip_hash_fields { 258 | ipv4.dstAddr; 259 | } 260 | 261 | field_list_calculation dstip_map_hash { 262 | input { 263 | dstip_hash_fields; 264 | } 265 | algorithm:crc16; 266 | output_width:8; 267 | } 268 | 269 | 270 | 271 | field_list resubmit_FL { 272 | standard_metadata; 273 | meta; 274 | 275 | } 276 | 277 | register tcp_session_is_SYN { 278 | //TOFINO: Width cannot be 1 or condition_lo will not be supported 279 | width : 8; 280 | instance_count: 256; 281 | } 282 | 283 | blackbox stateful_alu read_tcp_session_is_SYN{ 284 | //TOFINO: if syn = 1,write and read;else just read 285 | 286 | reg : tcp_session_is_SYN; 287 | condition_lo : tcp.syn == 1; 288 | update_lo_1_predicate:condition_lo; 289 | update_lo_1_value : 1 ; 290 | update_lo_2_predicate:not condition_lo; 291 | update_lo_2_value : register_lo; 292 | 293 | output_value : alu_lo; 294 | output_dst: meta.tcp_session_is_SYN; 295 | } 296 | 297 | register tcp_session_is_ACK { 298 | width : 8; 299 | instance_count:256; 300 | } 301 | 302 | blackbox stateful_alu read_tcp_session_is_ACK{ 303 | reg : tcp_session_is_ACK; 304 | condition_lo : tcp.ack == 1; 305 | update_lo_1_predicate:condition_lo; 306 | update_lo_1_value : 1 ; 307 | update_lo_2_predicate:not condition_lo; 308 | update_lo_2_value : register_lo; 309 | output_value : alu_lo; 310 | output_dst: meta.tcp_session_is_ACK; 311 | } 312 | register tcp_session_h2_reply_sa{ 313 | width : 1; 314 | instance_count: 8192; 315 | } 316 | /* 317 | blackbox stateful_alu read_tcp_session_h2_reply_sa{ 318 | reg : tcp_session_h2_reply_sa; 319 | update_lo_1_value : register_lo; 320 | output_value : alu_lo; 321 | output_dst: meta.tcp_session_h2_reply_sa; 322 | } 323 | 324 | blackbox stateful_alu write_tcp_session_h2_reply_sa{ 325 | reg : tcp_session_h2_reply_sa; 326 | update_lo_1_value :set_bitc; 327 | output_value : alu_lo; 328 | output_dst: meta.tcp_session_h2_reply_sa; 329 | } 330 | */ 331 | 332 | register h1_seq{ 333 | width : 32; 334 | instance_count: 256; 335 | } 336 | 337 | //TOFINO: We have to separate read and write, because we cannot refer to more than 3 metadata in a SALU. 338 | register h2_seq{ 339 | width : 32; 340 | instance_count: 256; 341 | } 342 | blackbox stateful_alu read_h2_seq{ 343 | reg : h2_seq; 344 | update_lo_1_value : register_lo; 345 | output_value : alu_lo; 346 | output_dst: meta.tcp_h2seq; 347 | } 348 | blackbox stateful_alu write_h2_seq{ 349 | reg : h2_seq; 350 | update_lo_1_value : meta.tcp_seqNo; 351 | output_value : alu_lo; 352 | output_dst : meta.tcp_h2seq; 353 | } 354 | /* 355 | blackbox stateful_alu inbound_h2_seq{ 356 | reg : h2_seq; 357 | update_lo_1_value :register_lo; 358 | output_value : register_lo + tcp.ackNo; 359 | output_dst: tcp.ackNo; 360 | } 361 | 362 | blackbox stateful_alu outbound_h2_seq{ 363 | reg : h2_seq; 364 | update_lo_1_value :register_lo; 365 | output_value : tcp.seqNo-register_lo; 366 | output_dst: tcp.seqNo; 367 | } 368 | */ 369 | register dstip_pktcount { 370 | width : 32; 371 | instance_count: 8192; 372 | } 373 | 374 | 375 | 376 | action _drop() { 377 | drop(); 378 | } 379 | //************************************for session_check table************************************ 380 | action lookup_session_map() 381 | { 382 | modify_field(meta.in_port,ig_intr_md.ingress_port); 383 | modify_field_with_hash_based_offset(meta.tcp_session_map_index,0,tcp_session_map_hash, 8); 384 | } 385 | 386 | action lookup_session_map_reverse() 387 | { 388 | modify_field(meta.in_port,ig_intr_md.ingress_port); 389 | modify_field_with_hash_based_offset(meta.reverse_tcp_session_map_index,0,reverse_tcp_session_map_hash, 8); 390 | } 391 | table session_check { 392 | actions { lookup_session_map;} 393 | } 394 | 395 | table session_check_reverse { 396 | actions { lookup_session_map_reverse;} 397 | } 398 | table read_state_SYN { 399 | actions {read_state_SYN_action; } 400 | } 401 | action read_state_SYN_action(){ 402 | read_tcp_session_is_SYN.execute_stateful_alu(meta.tcp_session_map_index); 403 | } 404 | 405 | table read_state_ACK { 406 | actions {read_state_ACK_action; } 407 | } 408 | action read_state_ACK_action(){ 409 | read_tcp_session_is_ACK.execute_stateful_alu(meta.tcp_session_map_index); 410 | } 411 | table read_state_h2 { 412 | //if the packet is synack, then write,or read; 413 | reads { 414 | tcp.syn:exact; 415 | tcp.ack:exact; 416 | } 417 | actions { 418 | read_state_h2_action; 419 | write_state_h2_action; 420 | } 421 | } 422 | action read_state_h2_action(){ 423 | read_h2_seq.execute_stateful_alu(meta.tcp_session_map_index); 424 | } 425 | 426 | action write_state_h2_action(){ 427 | write_h2_seq.execute_stateful_alu(meta.reverse_tcp_session_map_index); 428 | } 429 | 430 | action read_seq_action(){ 431 | read_h2_seq.execute_stateful_alu(meta.tcp_session_map_index); 432 | } 433 | table read_seq{ 434 | actions {read_seq_action;} 435 | } 436 | action write_seq_action(){ 437 | write_h2_seq.execute_stateful_alu(meta.reverse_tcp_session_map_index); 438 | } 439 | table write_seq{ 440 | actions {write_seq_action;} 441 | } 442 | 443 | 444 | 445 | 446 | table session_init_table { 447 | actions { 448 | sendback_sa; 449 | } 450 | } 451 | 452 | 453 | table session_complete_table { 454 | actions { 455 | sendh2syn; 456 | } 457 | } 458 | 459 | 460 | action set_resubmit() 461 | { 462 | modify_field(meta.reply_type, 4);//4 means just resubmit it 463 | } 464 | 465 | table handle_resubmit_table{ 466 | actions 467 | { 468 | set_resubmit; 469 | } 470 | } 471 | 472 | 473 | table relay_session_table 474 | { 475 | actions{ 476 | sendh2ack; 477 | } 478 | 479 | } 480 | 481 | action inbound_transformation() 482 | { 483 | add_to_field(tcp.ackNo,meta.tcp_h2seq); 484 | 485 | //subtract_from_field(tcp.checksum,meta.tcp_h2seq); 486 | 487 | modify_field(ipv4.diffserv,meta.tcp_session_map_index); 488 | modify_field(ipv4.identification,meta.reverse_tcp_session_map_index); 489 | 490 | modify_field(ig_intr_md_for_tm.ucast_egress_port, 136); 491 | } 492 | 493 | table inbound_tran_table2 494 | { 495 | actions{ 496 | inbound_transformation2; 497 | } 498 | } 499 | 500 | action inbound_transformation2() 501 | { 502 | subtract_from_field(tcp.checksum,tcp.ackNo); 503 | } 504 | 505 | table inbound_tran_table 506 | { 507 | actions{ 508 | inbound_transformation; 509 | } 510 | } 511 | action outbound_transformation() 512 | { 513 | //add_to_field(tcp.ackNo,meta.tcp_h2seq); 514 | add_to_field(tcp.ackNo,1234); 515 | //subtract_from_field(tcp.checksum,meta.tcp_h2seq); 516 | modify_field(ipv4.ttl,16); 517 | 518 | modify_field(ig_intr_md_for_tm.ucast_egress_port, 128); 519 | } 520 | 521 | table outbound_tran_table 522 | { 523 | actions{ 524 | outbound_transformation; 525 | } 526 | } 527 | 528 | 529 | 530 | 531 | //*************************forward_normal_table 532 | action set_forward_normal(port) 533 | { 534 | modify_field(meta.reply_type, 5); 535 | modify_field(meta.out_port,port); 536 | 537 | } 538 | 539 | table forward_normal_table 540 | { 541 | reads{ 542 | meta.in_port:exact; 543 | } 544 | actions{ 545 | _drop; 546 | set_forward_normal; 547 | } 548 | } 549 | 550 | table drop_table 551 | { 552 | actions{_drop;} 553 | } 554 | 555 | //**********for forward_table 556 | action forward_normal() 557 | { 558 | modify_field(ig_intr_md_for_tm.ucast_egress_port, meta.out_port); 559 | 560 | } 561 | action _resubmit() 562 | {// 04 563 | //resubmit(resubmit_FL); 564 | } 565 | 566 | 567 | action sendback_sa() 568 | { 569 | modify_field(tcp.syn,1); 570 | modify_field(tcp.ack,1); 571 | modify_field(tcp.seqNo,0x0) ; 572 | add_to_field(tcp.checksum,-0x11); 573 | 574 | add(tcp.ackNo,meta.tcp_seqNo,1); 575 | //add_to_field(tcp.ackNo,1); 576 | modify_field(ipv4.dstAddr, meta.ipv4_sa); 577 | modify_field(ipv4.srcAddr, meta.ipv4_da); 578 | modify_field(tcp.srcPort, meta.tcp_dp); 579 | modify_field(tcp.dstPort, meta.tcp_sp); 580 | modify_field(ethernet.dstAddr, meta.eth_sa); 581 | modify_field(ethernet.srcAddr, meta.eth_da); 582 | 583 | modify_field(ig_intr_md_for_tm.ucast_egress_port, meta.in_port); 584 | 585 | } 586 | 587 | action sendback_session_construct() 588 | { 589 | modify_field(tcp.fin,1); 590 | modify_field(standard_metadata.egress_spec, meta.in_port); 591 | 592 | } 593 | 594 | 595 | action setack(port) 596 | { 597 | modify_field(tcp.syn,0); 598 | modify_field(tcp.ack,1); 599 | modify_field(tcp.seqNo, meta.dstip_pktcount); 600 | modify_field(standard_metadata.egress_spec, port); 601 | } 602 | action sendh2ack() 603 | { 604 | modify_field(tcp.syn,0); 605 | modify_field(tcp.ack,1); 606 | 607 | add(tcp.ackNo,meta.tcp_h2seq,1); 608 | modify_field(ipv4.diffserv,meta.tcp_session_map_index); 609 | modify_field(ipv4.identification,meta.reverse_tcp_session_map_index); 610 | 611 | add_to_field(tcp.checksum,1); 612 | 613 | modify_field(tcp.seqNo,meta.tcp_ackNo) ; 614 | 615 | 616 | modify_field(ipv4.dstAddr, meta.ipv4_sa); 617 | modify_field(ipv4.srcAddr, meta.ipv4_da); 618 | modify_field(tcp.srcPort, meta.tcp_dp); 619 | modify_field(tcp.dstPort, meta.tcp_sp); 620 | modify_field(ethernet.dstAddr, meta.eth_sa); 621 | modify_field(ethernet.srcAddr, meta.eth_da); 622 | 623 | 624 | modify_field(ig_intr_md_for_tm.ucast_egress_port, 136); 625 | 626 | } 627 | 628 | action sendh2syn() 629 | { 630 | //flags changing from 0x10 to 0x2, that is 0xe 631 | modify_field(tcp.syn,1); 632 | modify_field(tcp.ack,0); 633 | add(tcp.seqNo,meta.tcp_seqNo,-1); 634 | modify_field(tcp.ackNo,0); 635 | //seq and ack both -0x1 636 | 637 | //for testing 638 | modify_field(ipv4.identification,meta.reverse_tcp_session_map_index); 639 | modify_field(ipv4.diffserv,meta.tcp_session_map_index); 640 | 641 | add_to_field(tcp.checksum,0x10); 642 | 643 | modify_field(ig_intr_md_for_tm.ucast_egress_port, 136); 644 | } 645 | 646 | //00 noreply 01 syn/ack back to h1 02 syn to h2 03 undifined 04 resubmit 05forward the packet 647 | table forward_table{ 648 | reads{ 649 | meta.reply_type:exact; 650 | } 651 | 652 | actions{ 653 | forward_normal;//reply_type:05 654 | _resubmit;//04 655 | sendh2ack;// 03 656 | sendh2syn;//02 657 | sendback_sa;//01 658 | sendback_session_construct; 659 | _drop;//0 660 | 661 | } 662 | } 663 | 664 | control ingress { 665 | if(ig_intr_md.ingress_port == 128){ 666 | apply(session_check); 667 | } 668 | else { 669 | apply(session_check_reverse); 670 | } 671 | /* 672 | apply(read_state_SYN); 673 | 674 | if(meta.tcp_session_is_SYN == 1) { 675 | apply(read_state_ACK); 676 | } 677 | if(meta.tcp_session_is_ACK == 1){ 678 | apply(read_state_h2); 679 | } 680 | */ 681 | 682 | if(meta.tcp_syn == 1 and meta.tcp_ack == 1){ 683 | apply(write_seq); 684 | } 685 | else{ 686 | apply(read_seq); 687 | } 688 | 689 | if (meta.tcp_syn == 1 and meta.tcp_ack == 0) 690 | { 691 | apply(session_init_table); 692 | } 693 | else if (meta.tcp_syn == 0 and meta.tcp_ack == 1 and meta.tcp_psh == 0/* and meta.tcp_session_is_SYN == 1*/) 694 | { 695 | apply(session_complete_table); 696 | } 697 | else if (meta.tcp_syn == 1 and meta.tcp_ack == 1) 698 | { 699 | apply(relay_session_table); 700 | } 701 | 702 | if(meta.tcp_psh == 1){ 703 | if (meta.in_port == 136 ) 704 | { 705 | apply(outbound_tran_table); 706 | } 707 | else if (meta.in_port == 128) 708 | { 709 | apply(inbound_tran_table); 710 | apply(inbound_tran_table2); 711 | } 712 | } 713 | 714 | } 715 | control egress { 716 | } 717 | 718 | -------------------------------------------------------------------------------- /DoS/tofino/syntry2.p4: -------------------------------------------------------------------------------- 1 | #include "tofino/stateful_alu_blackbox.p4" 2 | #include "tofino/intrinsic_metadata.p4" 3 | 4 | header_type ethernet_t { 5 | fields { 6 | dstAddr : 48; 7 | srcAddr : 48; 8 | etherType : 16; 9 | } 10 | } 11 | 12 | header_type ipv4_t { 13 | fields { 14 | version : 4; 15 | ihl : 4; 16 | diffserv : 8; 17 | totalLen : 16; 18 | identification : 16; 19 | flags : 3; 20 | fragOffset : 13; 21 | ttl : 8; 22 | protocol : 8; 23 | hdrChecksum : 16; 24 | srcAddr : 32; 25 | dstAddr: 32; 26 | } 27 | } 28 | parser start { 29 | //TOFINO: In tofino, the ingress_port meta_data is generated after parser, so nothing is done here. 30 | return parse_ethernet; 31 | 32 | } 33 | 34 | #define ETHERTYPE_IPV4 0x0800 35 | 36 | header ethernet_t ethernet; 37 | 38 | parser parse_ethernet { 39 | extract(ethernet); 40 | set_metadata(meta.eth_da,ethernet.dstAddr); 41 | set_metadata(meta.eth_sa,ethernet.srcAddr); 42 | return select(latest.etherType) { 43 | ETHERTYPE_IPV4 : parse_ipv4; 44 | default: ingress; 45 | } 46 | } 47 | 48 | header ipv4_t ipv4; 49 | 50 | field_list ipv4_checksum_list { 51 | ipv4.version; 52 | ipv4.ihl; 53 | ipv4.diffserv; 54 | ipv4.totalLen; 55 | ipv4.identification; 56 | ipv4.flags; 57 | ipv4.fragOffset; 58 | ipv4.ttl; 59 | ipv4.protocol; 60 | ipv4.srcAddr; 61 | ipv4.dstAddr; 62 | } 63 | field_list_calculation ipv4_checksum { 64 | input { 65 | ipv4_checksum_list; 66 | } 67 | algorithm : csum16; 68 | output_width : 16; 69 | } 70 | 71 | calculated_field ipv4.hdrChecksum { 72 | //verify ipv4_checksum; 73 | update ipv4_checksum; 74 | } 75 | 76 | #define IP_PROT_TCP 0x06 77 | 78 | parser parse_ipv4 { 79 | extract(ipv4); 80 | 81 | set_metadata(meta.ipv4_sa, ipv4.srcAddr); 82 | set_metadata(meta.ipv4_da, ipv4.dstAddr); 83 | //TOFINO: We cannot do calculations in parser 84 | //set_metadata(meta.tcpLength, ipv4.totalLen - 20); 85 | return select(ipv4.protocol) { 86 | IP_PROT_TCP : parse_tcp; 87 | default: ingress; 88 | } 89 | 90 | } 91 | 92 | header_type tcp_t { 93 | fields { 94 | srcPort : 16; 95 | dstPort : 16; 96 | seqNo : 32; 97 | ackNo : 32; 98 | dataOffset : 4; 99 | res : 4; 100 | flags : 3; 101 | ack: 1; 102 | psh: 1; 103 | rst: 1; 104 | syn: 1; 105 | fin: 1; 106 | window : 16; 107 | checksum : 16; 108 | urgentPtr : 16; 109 | } 110 | } 111 | 112 | 113 | header tcp_t tcp; 114 | 115 | parser parse_tcp { 116 | extract(tcp); 117 | //set_metadata(meta.tcp_sp, tcp.srcPort); 118 | //set_metadata(meta.tcp_dp, tcp.dstPort); 119 | set_metadata(meta.tcp_ack, tcp.ack); 120 | set_metadata(meta.tcp_psh, tcp.psh); 121 | set_metadata(meta.tcp_rst, tcp.rst); 122 | set_metadata(meta.tcp_syn, tcp.syn); 123 | set_metadata(meta.tcp_fin, tcp.fin); 124 | set_metadata(meta.tcp_seqNo, tcp.seqNo); 125 | //set_metadata(meta.tcp_seqNo_plus1, tcp.seqNo+1); 126 | //set_metadata(meta.tcp_seqNo_minus1, tcp.seqNo-1); 127 | set_metadata(meta.tcp_ackNo, tcp.ackNo); 128 | return ingress; 129 | } 130 | field_list tcp_checksum_list { 131 | ipv4.srcAddr; 132 | ipv4.dstAddr; 133 | 8'0; 134 | ipv4.protocol; 135 | meta.tcpLength; 136 | tcp.srcPort; 137 | tcp.dstPort; 138 | tcp.seqNo; 139 | tcp.ackNo; 140 | tcp.dataOffset; 141 | tcp.res; 142 | tcp.flags; 143 | tcp.ack; 144 | tcp.psh; 145 | tcp.rst; 146 | tcp.syn; 147 | tcp.fin; 148 | tcp.window; 149 | tcp.urgentPtr; 150 | payload; 151 | } 152 | 153 | field_list_calculation tcp_checksum { 154 | input { 155 | tcp_checksum_list; 156 | } 157 | algorithm : csum16; 158 | output_width : 16; 159 | } 160 | 161 | calculated_field tcp.checksum { 162 | //TOFINO: We cannot add if here on tofino. 163 | //verify tcp_checksum if(valid(tcp)); 164 | //update tcp_checksum if(valid(tcp)); 165 | update tcp_checksum; 166 | } 167 | 168 | 169 | header_type meta_t { 170 | fields { 171 | eth_sa:48; 172 | eth_da:48; 173 | ipv4_sa : 32; 174 | ipv4_da : 32; 175 | tcp_sp : 16; 176 | tcp_dp : 16; 177 | nhop_ipv4 : 32; 178 | if_ipv4_addr : 32; 179 | if_mac_addr : 48; 180 | is_ext_if : 1; 181 | tcpLength : 16; 182 | in_port : 8; 183 | out_port:8; 184 | 185 | tcp_syn:1; 186 | tcp_ack:1; 187 | reply_type:4;//0 drop 1 syn/ack back to h1 02 syn to h2 03 send h2 ack 04 resubmit 05 forward the packet as normal 188 | tcp_synack:1; 189 | tcp_psh:1; 190 | tcp_rst:1; 191 | tcp_fin:1; 192 | tcp_seqNo:32; 193 | tcp_seqNo_plus1:32; 194 | tcp_seqNo_minus1:32; 195 | tcp_h1seq:32; 196 | tcp_seqOffset:32; 197 | tcp_ackNo:32; 198 | tcp_h2seq:32; 199 | tcp_ackOffset:32; 200 | 201 | tcp_session_map_index : 8; 202 | reverse_tcp_session_map_index : 8; 203 | dstip_pktcount_map_index: 8; 204 | tcp_session_id : 16; 205 | 206 | dstip_pktcount:32;// how many packets have been sent to this dst IP address 207 | 208 | 209 | tcp_session_is_SYN: 1;// this session has sent a syn to switch 210 | tcp_session_is_ACK: 1;// this session has sent a ack to switchi 211 | tcp_session_h2_reply_sa:1;// h2 in this session has sent a sa to switch 212 | 213 | } 214 | 215 | } 216 | 217 | metadata meta_t meta; 218 | 219 | field_list l3_hash_fields { 220 | 221 | ipv4.srcAddr; 222 | ipv4.dstAddr; 223 | ipv4.protocol; 224 | tcp.srcPort; 225 | 226 | tcp.dstPort; 227 | } 228 | //get the hash according to the 5-touple of this packet 229 | field_list_calculation tcp_session_map_hash { 230 | input { 231 | l3_hash_fields; 232 | } 233 | algorithm: crc16; 234 | output_width: 8; 235 | 236 | } 237 | 238 | 239 | field_list reverse_l3_hash_fields { 240 | 241 | ipv4.dstAddr; 242 | ipv4.srcAddr; 243 | ipv4.protocol; 244 | 245 | tcp.dstPort; 246 | tcp.srcPort; 247 | 248 | 249 | } 250 | //reverse the src address and dst address, src port and dst port, to get the hash of the reply-packet of this packet 251 | //for example: h1 has a session with h2, according the reverse-hash of packet from h2, we can get the hash of packet from h1. 252 | field_list_calculation reverse_tcp_session_map_hash{ 253 | input { 254 | reverse_l3_hash_fields; 255 | } 256 | algorithm:crc16; 257 | output_width:8; 258 | 259 | } 260 | 261 | 262 | field_list dstip_hash_fields { 263 | ipv4.dstAddr; 264 | } 265 | 266 | field_list_calculation dstip_map_hash { 267 | input { 268 | dstip_hash_fields; 269 | } 270 | algorithm:crc16; 271 | output_width:8; 272 | } 273 | 274 | 275 | 276 | field_list resubmit_FL { 277 | standard_metadata; 278 | meta; 279 | 280 | } 281 | 282 | register tcp_session_is_SYN { 283 | //TOFINO: Width cannot be 1 or condition_lo will not be supported 284 | width : 8; 285 | instance_count: 8192; 286 | } 287 | 288 | blackbox stateful_alu read_tcp_session_is_SYN{ 289 | //TOFINO: if syn = 1,write and read;else just read 290 | reg : tcp_session_is_SYN; 291 | condition_lo : tcp.syn == 1; 292 | update_lo_1_predicate:condition_lo; 293 | update_lo_1_value : 1 ; 294 | update_lo_2_predicate:not condition_lo; 295 | update_lo_2_value : register_lo; 296 | output_value : alu_lo; 297 | output_dst: meta.tcp_session_is_SYN; 298 | } 299 | 300 | register tcp_session_is_ACK { 301 | width : 8; 302 | instance_count: 8192; 303 | } 304 | 305 | blackbox stateful_alu read_tcp_session_is_ACK{ 306 | reg : tcp_session_is_ACK; 307 | condition_lo : tcp.ack == 1; 308 | update_lo_1_predicate:condition_lo; 309 | update_lo_1_value : 1 ; 310 | update_lo_2_predicate:not condition_lo; 311 | update_lo_2_value : register_lo; 312 | output_value : alu_lo; 313 | output_dst: meta.tcp_session_is_ACK; 314 | } 315 | register tcp_session_h2_reply_sa{ 316 | width : 1; 317 | instance_count: 8192; 318 | } 319 | /* 320 | blackbox stateful_alu read_tcp_session_h2_reply_sa{ 321 | reg : tcp_session_h2_reply_sa; 322 | update_lo_1_value : register_lo; 323 | output_value : alu_lo; 324 | output_dst: meta.tcp_session_h2_reply_sa; 325 | } 326 | 327 | blackbox stateful_alu write_tcp_session_h2_reply_sa{ 328 | reg : tcp_session_h2_reply_sa; 329 | update_lo_1_value :set_bitc; 330 | output_value : alu_lo; 331 | output_dst: meta.tcp_session_h2_reply_sa; 332 | } 333 | */ 334 | register h1_seq{ 335 | width : 32; 336 | instance_count: 8192; 337 | } 338 | 339 | //TOFINO: We have to separate read and write, because we cannot refer to more than 3 metadata in a SALU. 340 | register h2_seq{ 341 | width : 32; 342 | instance_count: 8192; 343 | } 344 | blackbox stateful_alu read_h2_seq{ 345 | reg : h2_seq; 346 | update_lo_1_value : register_lo; 347 | output_value : alu_lo; 348 | output_dst: meta.tcp_h2seq; 349 | } 350 | blackbox stateful_alu write_h2_seq{ 351 | reg : h2_seq; 352 | update_lo_1_value : meta.tcp_seqNo; 353 | output_value : alu_lo; 354 | output_dst : meta.tcp_h2seq; 355 | } 356 | /* 357 | blackbox stateful_alu inbound_h2_seq{ 358 | reg : h2_seq; 359 | update_lo_1_value :register_lo; 360 | output_value : register_lo + tcp.ackNo; 361 | output_dst: tcp.ackNo; 362 | } 363 | 364 | blackbox stateful_alu outbound_h2_seq{ 365 | reg : h2_seq; 366 | update_lo_1_value :register_lo; 367 | output_value : tcp.seqNo-register_lo; 368 | output_dst: tcp.seqNo; 369 | } 370 | */ 371 | register dstip_pktcount { 372 | width : 32; 373 | instance_count: 8192; 374 | } 375 | 376 | 377 | 378 | action _drop() { 379 | drop(); 380 | } 381 | //************************************for session_check table************************************ 382 | action lookup_session_map() 383 | { 384 | modify_field(meta.in_port,ig_intr_md.ingress_port); 385 | modify_field_with_hash_based_offset(meta.tcp_session_map_index,0,tcp_session_map_hash, 8); 386 | } 387 | 388 | action lookup_session_map_reverse() 389 | { 390 | modify_field(meta.in_port,ig_intr_md.ingress_port); 391 | modify_field_with_hash_based_offset(meta.reverse_tcp_session_map_index,0,reverse_tcp_session_map_hash, 8); 392 | } 393 | table session_check { 394 | actions { lookup_session_map;} 395 | } 396 | 397 | table session_check_reverse { 398 | actions { lookup_session_map_reverse;} 399 | } 400 | table read_state_SYN { 401 | actions {read_state_SYN_action; } 402 | } 403 | action read_state_SYN_action(){ 404 | read_tcp_session_is_SYN.execute_stateful_alu(meta.tcp_session_map_index); 405 | } 406 | 407 | table read_state_ACK { 408 | actions {read_state_ACK_action; } 409 | } 410 | action read_state_ACK_action(){ 411 | read_tcp_session_is_ACK.execute_stateful_alu(meta.tcp_session_map_index); 412 | } 413 | table read_state_h2 { 414 | //if the packet is synack, then write,or read; 415 | reads { 416 | tcp.syn:exact; 417 | tcp.ack:exact; 418 | } 419 | actions { 420 | read_state_h2_action; 421 | write_state_h2_action; 422 | } 423 | } 424 | action read_state_h2_action(){ 425 | read_h2_seq.execute_stateful_alu(meta.tcp_session_map_index); 426 | } 427 | 428 | action write_state_h2_action(){ 429 | write_h2_seq.execute_stateful_alu(meta.tcp_session_map_index); 430 | } 431 | 432 | //**************************for session_init_table******************* 433 | action init_session() 434 | { 435 | modify_field(meta.reply_type,1);//1 means forward_table should return a SA to h1i 436 | } 437 | 438 | table session_init_table { 439 | actions { 440 | //init_session; 441 | sendback_sa; 442 | } 443 | 444 | } 445 | 446 | 447 | //*******************for session_complete_table********************** 448 | 449 | action complete_session() 450 | { 451 | modify_field(meta.reply_type,2);// 2 means forward_table should send a syn to h2 452 | } 453 | table session_complete_table { 454 | actions { complete_session;} 455 | } 456 | 457 | //*******************************for handle_resubmit_table* 458 | action set_resubmit() 459 | { 460 | modify_field(meta.reply_type, 4);//4 means just resubmit it 461 | } 462 | 463 | table handle_resubmit_table{ 464 | actions 465 | { 466 | set_resubmit; 467 | } 468 | 469 | } 470 | 471 | // ********************************for relay_session_table 472 | // 473 | action relay_session() 474 | { 475 | modify_field(meta.reply_type,3);//not to drop we should return a ack to h2 (don't forget to swap the ip and macs 476 | } 477 | table relay_session_table 478 | { 479 | actions{ 480 | relay_session; 481 | } 482 | 483 | } 484 | 485 | action inbound_transformation() 486 | { 487 | //subtract(meta.tcp_ackOffset,meta.tcp_ackNo,0); 488 | 489 | add(meta.tcp_ackNo,meta.tcp_ackNo,meta.tcp_h2seq); 490 | modify_field(tcp.ackNo,meta.tcp_ackNo); 491 | modify_field(ipv4.ttl,32); 492 | 493 | } 494 | 495 | table inbound_tran_table 496 | { 497 | actions{ 498 | inbound_transformation; 499 | } 500 | } 501 | 502 | action outbound_transformation() 503 | { 504 | subtract(meta.tcp_seqNo,meta.tcp_seqNo,meta.tcp_h2seq); 505 | //add(meta.tcp_seqNo,meta.tcp_seqOffset,0); 506 | modify_field(tcp.seqNo,meta.tcp_seqNo); 507 | modify_field(ipv4.ttl,32); 508 | 509 | } 510 | 511 | table outbound_tran_table 512 | { 513 | actions{ 514 | outbound_transformation; 515 | } 516 | } 517 | 518 | 519 | 520 | 521 | //*************************forward_normal_table 522 | action set_forward_normal(port) 523 | { 524 | modify_field(meta.reply_type, 5); 525 | modify_field(meta.out_port,port); 526 | 527 | } 528 | 529 | table forward_normal_table 530 | { 531 | reads{ 532 | meta.in_port:exact; 533 | } 534 | actions{ 535 | _drop; 536 | set_forward_normal; 537 | } 538 | } 539 | 540 | table drop_table 541 | { 542 | actions{_drop;} 543 | } 544 | 545 | //**********for forward_table 546 | action forward_normal() 547 | { 548 | modify_field(ig_intr_md_for_tm.ucast_egress_port, meta.out_port); 549 | 550 | } 551 | action _resubmit() 552 | {// 04 553 | //resubmit(resubmit_FL); 554 | } 555 | 556 | 557 | action sendback_sa() 558 | { 559 | modify_field(tcp.syn,1); 560 | modify_field(tcp.ack,1); 561 | modify_field(tcp.seqNo,0x0) ; 562 | 563 | //modify_field(tcp.ackNo,meta.tcp_seqNo_plus1); 564 | add(tcp.ackNo,meta.tcp_seqNo,1); 565 | //add_to_field(tcp.ackNo,1); 566 | modify_field(ipv4.dstAddr, meta.ipv4_sa); 567 | modify_field(ipv4.srcAddr, meta.ipv4_da); 568 | modify_field(tcp.srcPort, meta.tcp_dp); 569 | modify_field(tcp.dstPort, meta.tcp_sp); 570 | modify_field(ethernet.dstAddr, meta.eth_sa); 571 | modify_field(ethernet.srcAddr, meta.eth_da); 572 | 573 | modify_field(ig_intr_md_for_tm.ucast_egress_port, meta.in_port); 574 | 575 | } 576 | 577 | action sendback_session_construct() 578 | { 579 | modify_field(tcp.fin,1); 580 | modify_field(standard_metadata.egress_spec, meta.in_port); 581 | 582 | } 583 | 584 | 585 | action setack(port) 586 | { 587 | modify_field(tcp.syn,0); 588 | modify_field(tcp.ack,1); 589 | modify_field(tcp.seqNo, meta.dstip_pktcount); 590 | modify_field(standard_metadata.egress_spec, port); 591 | } 592 | action sendh2ack() 593 | { 594 | modify_field(tcp.syn,0); 595 | modify_field(tcp.ack,1); 596 | // add_to_field(meta.tcp_seqNo,1); 597 | // modify_field(tcp.ackNo, meta.tcp_seqNo_plus1); 598 | add(tcp.ackNo,meta.tcp_seqNo,1); 599 | 600 | modify_field(tcp.seqNo,meta.tcp_ackNo) ; 601 | modify_field(ipv4.dstAddr, meta.ipv4_sa); 602 | modify_field(ipv4.srcAddr, meta.ipv4_da); 603 | modify_field(tcp.srcPort, meta.tcp_dp); 604 | modify_field(tcp.dstPort, meta.tcp_sp); 605 | modify_field(ethernet.dstAddr, meta.eth_sa); 606 | modify_field(ethernet.srcAddr, meta.eth_da); 607 | 608 | modify_field(standard_metadata.egress_spec, meta.in_port); 609 | 610 | } 611 | action sendh2syn(port) 612 | { 613 | modify_field(tcp.syn,1); 614 | modify_field(tcp.ack,0); 615 | //modify_field(tcp.seqNo, meta.tcp_seqNo_minus1); 616 | add(tcp.seqNo,meta.tcp_seqNo,-1); 617 | modify_field(tcp.ackNo,0); 618 | 619 | modify_field(standard_metadata.egress_spec,port); 620 | } 621 | 622 | //00 noreply 01 syn/ack back to h1 02 syn to h2 03 undifined 04 resubmit 05forward the packet 623 | table forward_table{ 624 | reads{ 625 | meta.reply_type:exact; 626 | } 627 | 628 | actions{ 629 | forward_normal;//reply_type:05 630 | _resubmit;//04 631 | sendh2ack;// 03 632 | sendh2syn;//02 633 | sendback_sa;//01 634 | sendback_session_construct; 635 | _drop;//0 636 | 637 | } 638 | } 639 | 640 | control ingress { 641 | /* 642 | meta.tcp_session_map_index (and other meta datas) will be correctly set in this stage. 643 | Here we use different hash fields for inbound and outbound packets 644 | However, tofino forbids modifying a metadata field with multiple hash calculation units in a table. 645 | So have to use different tables 646 | */ 647 | if(ig_intr_md.ingress_port == 128){ 648 | apply(session_check); 649 | } 650 | else { 651 | apply(session_check_reverse); 652 | } 653 | 654 | /* 655 | Every packet goes through this stage. 656 | SYN packets update the registers, while otherpackets just read. 657 | meta.tcp_session_is_SYN is set. 658 | */ 659 | 660 | 661 | apply(read_state_SYN); 662 | 663 | 664 | /* 665 | The packets from a connection whose SYN is received goes through this stage. 666 | ACK packets update the registers, while otherpackets just read. 667 | meta.tcp_session_is_ACK is set. 668 | */ 669 | 670 | 671 | if(meta.tcp_session_is_SYN == 1) { 672 | apply(read_state_ACK); 673 | } 674 | 675 | /* 676 | The packets from a completed connection enter this stage. 677 | They could be payload packets from h1 or SYNACK from h2. 678 | The latter update the registers while the former just read. 679 | */ 680 | 681 | if(meta.tcp_session_is_ACK == 1){ 682 | apply(read_state_h2); 683 | } 684 | 685 | /* 686 | The next stage decides the packets' fate based on the metadatas obtained in previous stages. 687 | For h1SYN, send h1SYNACK 688 | For h2ACK, send h2SYN 689 | For h2SYNACK, send h2ACK 690 | For payloads, do Seq/Ack transformation. 691 | meta.reply_type is set. 692 | 693 | */ 694 | 695 | if (meta.tcp_syn == 1 and meta.tcp_ack == 0) 696 | { 697 | apply(session_init_table); 698 | } 699 | else if (meta.tcp_syn == 0 and meta.tcp_ack == 1) 700 | { 701 | apply(session_complete_table); 702 | } 703 | else if (meta.tcp_syn == 1 and meta.tcp_ack == 1) 704 | { 705 | apply(relay_session_table); //check if it is syn/ack and change the register 706 | } 707 | else if (meta.tcp_session_is_ACK == 1){ 708 | if (meta.in_port == 2 ) 709 | { 710 | apply(outbound_tran_table); 711 | } 712 | else if (meta.in_port == 1) 713 | { 714 | apply(inbound_tran_table); 715 | } 716 | apply(forward_normal_table); 717 | } 718 | 719 | /* Based on meta.reply_type, do modfications and forward*/ 720 | //apply(forward_table); 721 | 722 | } 723 | control egress { 724 | } 725 | 726 | -------------------------------------------------------------------------------- /DoS/tofino/syntry3.p4: -------------------------------------------------------------------------------- 1 | #include "tofino/stateful_alu_blackbox.p4" 2 | #include "tofino/intrinsic_metadata.p4" 3 | 4 | header_type ethernet_t { 5 | fields { 6 | dstAddr : 48; 7 | srcAddr : 48; 8 | etherType : 16; 9 | } 10 | } 11 | 12 | header_type ipv4_t { 13 | fields { 14 | version : 4; 15 | ihl : 4; 16 | diffserv : 8; 17 | totalLen : 16; 18 | identification : 16; 19 | flags : 3; 20 | fragOffset : 13; 21 | ttl : 8; 22 | protocol : 8; 23 | hdrChecksum : 16; 24 | srcAddr : 32; 25 | dstAddr: 32; 26 | } 27 | } 28 | parser start { 29 | //TOFINO: In tofino, the ingress_port meta_data is generated after parser, so nothing is done here. 30 | return parse_ethernet; 31 | 32 | } 33 | 34 | #define ETHERTYPE_IPV4 0x0800 35 | 36 | header ethernet_t ethernet; 37 | 38 | parser parse_ethernet { 39 | extract(ethernet); 40 | set_metadata(meta.eth_da,ethernet.dstAddr); 41 | set_metadata(meta.eth_sa,ethernet.srcAddr); 42 | return select(latest.etherType) { 43 | ETHERTYPE_IPV4 : parse_ipv4; 44 | default: ingress; 45 | } 46 | } 47 | 48 | @pragma pa_fragment ingress ipv4.hdrChecksum 49 | @pragma pa_fragment egress ipv4.hdrChecksum 50 | @pragma pa_fragment ingress ipv4.protocol 51 | @pragma pa_fragment egress ipv4.protocol 52 | 53 | header ipv4_t ipv4; 54 | 55 | field_list ipv4_checksum_list { 56 | ipv4.version; 57 | ipv4.ihl; 58 | ipv4.diffserv; 59 | ipv4.totalLen; 60 | ipv4.identification; 61 | ipv4.flags; 62 | ipv4.fragOffset; 63 | ipv4.ttl; 64 | ipv4.protocol; 65 | ipv4.srcAddr; 66 | ipv4.dstAddr; 67 | } 68 | field_list_calculation ipv4_checksum { 69 | input { 70 | ipv4_checksum_list; 71 | } 72 | algorithm : csum16; 73 | output_width : 16; 74 | } 75 | 76 | calculated_field ipv4.hdrChecksum { 77 | verify ipv4_checksum; 78 | update ipv4_checksum; 79 | } 80 | 81 | #define IP_PROT_TCP 0x06 82 | 83 | parser parse_ipv4 { 84 | extract(ipv4); 85 | set_metadata(meta.ipv4_sa, ipv4.srcAddr); 86 | set_metadata(meta.ipv4_da, ipv4.dstAddr); 87 | //TOFINO: We cannot do calculations in parser 88 | //set_metadata(meta.tcpLength, ipv4.totalLen - 20); 89 | return select(ipv4.protocol) { 90 | IP_PROT_TCP : parse_tcp; 91 | default: ingress; 92 | } 93 | 94 | } 95 | 96 | header_type tcp_t { 97 | fields { 98 | srcPort : 16; 99 | dstPort : 16; 100 | seqNo : 32; 101 | ackNo : 32; 102 | dataOffset : 4; 103 | res : 4; 104 | flags : 8; 105 | window : 16; 106 | checksum : 16; 107 | urgentPtr : 16; 108 | } 109 | } 110 | 111 | @pragma pa_fragment egress tcp.checksum 112 | @pragma pa_fragment ingress tcp.checksum 113 | @pragma pa_fragment egress tcp.urgentPtr 114 | @pragma pa_fragment ingress tcp.urgentPtr 115 | header tcp_t tcp; 116 | 117 | parser parse_tcp { 118 | extract(tcp); 119 | set_metadata(meta.tcp_sp, tcp.srcPort); 120 | set_metadata(meta.tcp_dp, tcp.dstPort); 121 | /* 122 | set_metadata(meta.tcp_ack, tcp.ack); 123 | set_metadata(meta.tcp_psh, tcp.psh); 124 | set_metadata(meta.tcp_rst, tcp.rst); 125 | set_metadata(meta.tcp_syn, tcp.syn); 126 | set_metadata(meta.tcp_fin, tcp.fin); 127 | */ 128 | set_metadata(meta.tcp_seqNo, tcp.seqNo); 129 | set_metadata(meta.tcp_ackNo, tcp.ackNo); 130 | return ingress; 131 | } 132 | /* 133 | field_list tcp_checksum_list { 134 | ipv4.srcAddr; 135 | ipv4.dstAddr; 136 | 8'0; 137 | ipv4.protocol; 138 | tcp.srcPort; 139 | tcp.dstPort; 140 | tcp.seqNo; 141 | tcp.ackNo; 142 | tcp.dataOffset; 143 | tcp.res; 144 | tcp.flags; 145 | tcp.window; 146 | tcp.urgentPtr; 147 | payload; 148 | } 149 | 150 | field_list_calculation tcp_checksum { 151 | input { 152 | tcp_checksum_list; 153 | } 154 | algorithm : csum16; 155 | output_width : 16; 156 | } 157 | 158 | calculated_field tcp.checksum { 159 | //TOFINO: We cannot add if here on tofino. 160 | update tcp_checksum; 161 | } 162 | */ 163 | header_type meta_t { 164 | fields { 165 | tcpLength : 16; 166 | eth_da:48; 167 | eth_sa:48; 168 | ipv4_sa : 32; 169 | 170 | ipv4_da : 32; 171 | 172 | tcp_sp : 16; 173 | 174 | tcp_dp : 16; 175 | tcp_seqNo:32; 176 | tcp_ackNo:32; 177 | zeros:8; 178 | } 179 | 180 | } 181 | 182 | metadata meta_t meta; 183 | 184 | field_list l3_hash_fields { 185 | 186 | ipv4.srcAddr; 187 | ipv4.dstAddr; 188 | ipv4.protocol; 189 | tcp.srcPort; 190 | 191 | tcp.dstPort; 192 | } 193 | //get the hash according to the 5-touple of this packet 194 | field_list_calculation tcp_session_map_hash { 195 | input { 196 | l3_hash_fields; 197 | } 198 | algorithm: crc16; 199 | output_width: 8; 200 | 201 | } 202 | 203 | 204 | field_list reverse_l3_hash_fields { 205 | 206 | ipv4.dstAddr; 207 | ipv4.srcAddr; 208 | ipv4.protocol; 209 | 210 | tcp.dstPort; 211 | tcp.srcPort; 212 | 213 | 214 | } 215 | //reverse the src address and dst address, src port and dst port, to get the hash of the reply-packet of this packet 216 | //for example: h1 has a session with h2, according the reverse-hash of packet from h2, we can get the hash of packet from h1. 217 | field_list_calculation reverse_tcp_session_map_hash{ 218 | input { 219 | reverse_l3_hash_fields; 220 | } 221 | algorithm:crc16; 222 | output_width:8; 223 | 224 | } 225 | 226 | 227 | field_list dstip_hash_fields { 228 | ipv4.dstAddr; 229 | } 230 | 231 | field_list_calculation dstip_map_hash { 232 | input { 233 | dstip_hash_fields; 234 | } 235 | algorithm:crc16; 236 | output_width:8; 237 | } 238 | 239 | 240 | table session_init_table { 241 | actions { 242 | sendback_sa; 243 | } 244 | } 245 | 246 | 247 | 248 | action sendback_sa() 249 | { 250 | //subtract(meta.tcpLength,20); 251 | modify_field(meta.tcpLength,0); 252 | modify_field(meta.zeros,0); 253 | modify_field(tcp.flags,0x12); 254 | add_to_field(tcp.checksum,-0x11); 255 | /* 256 | modify_field(tcp.syn,1); 257 | modify_field(tcp.ack,1); 258 | */ 259 | modify_field(tcp.seqNo,0x0) ; 260 | add(tcp.ackNo,meta.tcp_seqNo,1); 261 | modify_field(ipv4.dstAddr, meta.ipv4_sa); 262 | modify_field(ipv4.srcAddr, meta.ipv4_da); 263 | modify_field(tcp.srcPort, meta.tcp_dp); 264 | modify_field(tcp.dstPort, meta.tcp_sp); 265 | modify_field(ethernet.dstAddr, meta.eth_sa); 266 | modify_field(ethernet.srcAddr, meta.eth_da); 267 | 268 | modify_field(ig_intr_md_for_tm.ucast_egress_port, ig_intr_md.ingress_port); 269 | 270 | } 271 | 272 | 273 | control ingress { 274 | apply(session_init_table); 275 | 276 | } 277 | control egress { 278 | } 279 | 280 | -------------------------------------------------------------------------------- /DoS/tofino/test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013-present Barefoot Networks, Inc. 2 | # # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | 14 | """ 15 | Simple PTF test for synproxy.p4 16 | """ 17 | 18 | import pd_base_tests 19 | 20 | from ptf import config 21 | from ptf.testutils import * 22 | from ptf.thriftutils import * 23 | 24 | from synproxy.p4_pd_rpc.ttypes import * 25 | from res_pd_rpc.ttypes import * 26 | 27 | class SYNProxyTest(pd_base_tests.ThriftInterfaceDataPlane): 28 | def __init__(self): 29 | pd_base_tests.ThriftInterfaceDataPlane.__init__(self, 30 | ["synproxy"]) 31 | 32 | # The setUp() method is used to prepare the test fixture. Typically 33 | # you would use it to establich connection to the Thrift server. 34 | # 35 | # You can also put the initial device configuration there. However, 36 | # if during this process an error is encountered, it will be considered 37 | # as a test error (meaning the test is incorrect), 38 | # rather than a test failure 39 | def setUp(self): 40 | pd_base_tests.ThriftInterfaceDataPlane.setUp(self) 41 | 42 | self.sess_hdl = self.conn_mgr.client_init() 43 | self.dev = 0 44 | self.dev_tgt = DevTarget_t(self.dev, hex_to_i16(0xFFFF)) 45 | 46 | print("\nConnected to Device %d, Session %d" % ( 47 | self.dev, self.sess_hdl)) 48 | 49 | # This method represents the test itself. Typically you would want to 50 | # configure the device (e.g. by populating the tables), send some 51 | # traffic and check the results. 52 | # 53 | # For more flexible checks, you can import unittest module and use 54 | # the provided methods, such as unittest.assertEqual() 55 | # 56 | # Do not enclose the code into try/except/finally -- this is done by 57 | # the framework itself 58 | def runTest(self): 59 | # Test Parameters 60 | mac_da = "00:11:11:11:11:11" 61 | 62 | 63 | print("Enabling ports (physical interface 1 and 2 as 40G)") 64 | ingress_port = 128 65 | egress_port = 136 66 | speed40G = 4 67 | dev = self.dev 68 | channel = 0 69 | self.pltfm_pm.pltfm_pm_port_add(dev,ingress_port,speed40G,channel) 70 | self.pltfm_pm.pltfm_pm_port_add(dev,egress_port,speed40G,channel) 71 | self.pltfm_pm.pltfm_pm_port_enable(dev,ingress_port) 72 | self.pltfm_pm.pltfm_pm_port_enable(dev,egress_port) 73 | 74 | self.client.session_init_table_set_default_action_sendback_sa(self.sess_hdl,self.dev_tgt); 75 | self.client.session_complete_table_set_default_action_sendh2syn(self.sess_hdl,self.dev_tgt); 76 | self.client.relay_session_table_set_default_action_sendh2ack(self.sess_hdl,self.dev_tgt); 77 | self.client.inbound_tran_table_set_default_action_inbound_transformation(self.sess_hdl,self.dev_tgt); 78 | self.client.outbound_tran_table_set_default_action_outbound_transformation(self.sess_hdl,self.dev_tgt); 79 | #self.client.outbound_tran_table_set_default_action_outbound_transformation(self.sess_hdl,self.dev_tgt); 80 | 81 | self.client.session_check_set_default_action_lookup_session_map(self.sess_hdl,self.dev_tgt); 82 | self.client.session_check_reverse_set_default_action_lookup_session_map_reverse(self.sess_hdl,self.dev_tgt); 83 | 84 | self.conn_mgr.complete_operations(self.sess_hdl) 85 | while(True): 86 | pass 87 | ''' 88 | print("Sending packet with DST MAC=%s into port %d" % 89 | (mac_da, ingress_port)) 90 | pkt = simple_tcp_packet(eth_dst=mac_da, 91 | eth_src='00:55:55:55:55:55', 92 | ip_dst='10.0.0.1', 93 | ip_id=101, 94 | ip_ttl=64, 95 | ip_ihl=5) 96 | send_packet(self, ingress_port, pkt) 97 | time.sleep(1) 98 | print("Expecting packet on port %d" % egress_port) 99 | verify_packets(self, pkt, [egress_port]) 100 | ''' 101 | 102 | # Use this method to return the DUT to the initial state by cleaning 103 | # all the configuration and clearing up the connection 104 | def tearDown(self): 105 | try: 106 | print("Clearing table entries") 107 | for table in self.entries.keys(): 108 | delete_func = "self.client." + table + "_table_delete" 109 | for entry in self.entries[table]: 110 | exec delete_func + "(self.sess_hdl, self.dev, entry)" 111 | except: 112 | print("Error while cleaning up. ") 113 | print("You might need to restart the driver") 114 | finally: 115 | self.conn_mgr.complete_operations(self.sess_hdl) 116 | self.conn_mgr.client_cleanup(self.sess_hdl) 117 | print("Closed Session %d" % self.sess_hdl) 118 | pd_base_tests.ThriftInterfaceDataPlane.tearDown(self) 119 | -------------------------------------------------------------------------------- /DoS/tofino/test.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhangmenghao/p4research/8d1fe7a94c4c495d5ba4d27ce19ea2ef4b9be6e8/DoS/tofino/test.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DDoS Mitigation Using Switching ASICs 2 | Here in this repository, we implemented multiple Denial-of-Service (DoS) defense modules in switching ASICs to protect servers from DoS attacks. 3 | 4 | Modern programmable switches now have enough power to implement most of the DoS defense methods directly. However, traditional DoS defense approaches are all memory-intensive, while switch only has limited resources, which makes it non-trivial to migrate these approach directly. We carefully design various techniques such as memory reuse, compromising accuracy, hash-based compressing to fully exploit the potential of a switch. 5 | 6 | The whole mechanism here is completely transparent to all devices in the network. The whole system can be automatically turned on or off according to the traffic passing through it, which make our system incur negative impacts on legitimate traffic as low as possible. 7 | 8 | We mainly aim at provides protection for flooding-based DoS attacks, including spoofing attacks (e.g., *UDP flood*, *ICMP flood*, *TCP SYN flood*, *DNS Reflection*) and unspoofing attacks (e.g. *data flood*, *Sloworis attack*, *NAPTHA attack*). 9 | 10 | ## Spoofing Attacks 11 | We use a whitelist to limit the overall throughput while guaranteeing a higher priority for those source-IPs in the whitelist. The whitelist can be built from two sources, one is migrated directly from the whiltelist of TCP defense mechanism, the other is obtained from DNS or ICMP tracking table. 12 | ### Reflector Attacks 13 | Tracking table, as mentioned above, is a great way to protect a network from reflection attacks. Take DNS reflecion attack as an example. We can track every DNS request message sent out of the network, and DNS reply can re-enter the network only if its corresponding request packet was recorded. 14 | 15 | ### SYN FLOOD 16 | Our policy for migrating spoofing SYN floods is SYN proxy, originating from the idea of SYN-cookie. We use two private keys to calculate syn cookie value, among with original 5-tuple of the connection. The two keys are distributed by control plane, and the older one will be updated after a certain time period for security considerations. When receiving a ACK from a unknown connection, the switch will calculate two cookie values using two keys respectively and compare them with ACK number carried in the packet. Drop the packet if there are no matches. 17 | 18 | 19 | ## Other Unspoofing Attacks 20 | Heavy hitter detector is adapted for unspoofing packets. The number and the total packet size of connections established by the same IP address are recorded using count-min sketch. If either of these two data is abnormal (way higher than threshold, for example), the corresponding source IP address will be inserted into blacklist table, which is basically a filter at the very beginning of the whole system. Packets that hit the filter are recognized as malicious ones and will be dropped immediately. Out-date entries in both blacklist and whitelist are removed to reduce the memory costs. 21 | 22 | --------------------------------------------------------------------------------