#import "labtemplate.typ": * #show: nudtlabpaper.with(title: "SDN可编程网络实验", author1: "程景愉", id1: "202302723005", advisor: " 胡罡", jobtitle: "教授", lab: "306-707", date: "2025.11.18", header_str: "《网络工程》实验报告", ) #set page(header: [ #set par(spacing: 6pt) #align(center)[#text(size: 11pt)[《网络工程》实验报告]] #v(-0.3em) #line(length: 100%, stroke: (thickness: 1pt)) ],) #show heading: it => box(width: 100%)[ #v(0.50em) #set text(font: hei) #it.body ] #outline(title: "目录",depth: 3, indent: 1em) #pagebreak() #outline( title: [图目录], target: figure.where(kind: image), ) #show heading: it => box(width: 100%)[ #v(0.50em) #set text(font: hei) #counter(heading).display() // #h(0.5em) #it.body ] #set enum(indent: 0.5em,body-indent: 0.5em,) #pagebreak() = 实验概述 == 实验内容 #para[] 本次综合实验中分有三个实验: + 基于 SDN 交换机源码处理openflow协议消息 + 虚拟网络拓扑实验 + DDoS 网络攻击的 SDN 实验 #para[ 本实验报告重点分析第一个实验的实现细节,并在最后补充介绍本小组的选做实验。 ] == 实验要求 1. 熟悉Openbox-S4的基本功能 2. 熟悉OpenFlow协议的基本消息格式 3. 熟悉OpenFlow协议的基本消息处理流程 // Display inline code in a small box // that retains the correct baseline. #show raw.where(block: false): it => box( text(font: ("JetBrainsMono NF","Noto Fangsong KSS Rotated"), it), fill: luma(240), inset: (x: 3pt, y: 0pt), outset: (y: 3pt), radius: 2pt, ) // Display block code in a larger block // with more padding. #show raw.where(block: true): it => box( text(font: ("JetBrainsMono NF","Noto Fangsong KSS Rotated"), it), fill: luma(240), inset: 10pt, radius: 4pt, width: 100%, ) = 编写SDN交换机源码处理OpenFlow协议消息 #para[ 本次实验在`main_user_openflow.c`文件中实现了OpenFlow协议处理逻辑。代码通过多个函数处理不同类型的OpenFlow消息,包括Hello消息、Features Request消息、Flow Stats Request消息等。每个函数都根据消息类型生成相应的回复消息,并通过`send_openflow_message`函数发送给控制器。以下将逐一分析每个函数的实现细节。 ] == 本次实验所编写的协议 #para[ 本次实验实现了OpenFlow协议中的大部分消息处理功能。实验代码涵盖了从交换机特性查询到流表统计、端口统计等多种消息类型的处理。以下是实验编写协议的总结。 ] === 实现的协议 - OFPT_FEATURES_REQUEST:用于获取交换机支持的流表数量、缓冲区大小等特性信息。对应的处理函数为`handle_opfmsg_features_request`。 - OFPT_GET_CONFIG_REQUEST:用于查询交换机的配置信息,如Miss Send Length等。对应的处理函数为`handle_ofpmsg_get_config_request`。 - OFPT_MULTIPART_REQUEST:用于处理多种统计信息请求,包括交换机描述信息、流表信息、端口统计信息等。对应的处理函数包括: - `handle_ofpmsg_desc` // - `handle_ofpmsg_flow_stats` // - `handle_ofpmsg_aggregate` - `handle_ofpmsg_table` - `handle_ofpmsg_port_stats` - `handle_ofpmsg_group_features` - `handle_ofpmsg_port_desc` - OFPT_PACKET_OUT:用于处理控制器发送的数据包,并根据动作指示将数据包从指定端口发送出去。对应的处理函数为`handle_ofpmsg_packet_out`。 - OFPT_ROLE_REQUEST:用于配置交换机的角色(如主控制器、从控制器等)。对应的处理函数为`handle__opfmsg_role_request`。 == 相关数据结构 #para[ 在`main_user_openflow.c`中,定义了一些关键的数据结构和全局变量,用于处理OpenFlow协议的消息。主要的数据结构包括`ofp_header`、`ofp_switch_features`、`ofp_flow_stats`和`ofp_port_stats`等。这些数据结构用于处理OpenFlow协议中的不同消息类型,如交换机特性请求、流表统计请求、端口统计请求等。 ] #para[ `ofp_header`结构体用于表示OpenFlow消息头,包含协议版本、消息类型、消息长度和事务ID等字段。`ofp_switch_features`结构体用于表示交换机的特性信息,如数据路径ID、缓冲区数量、流表数量等。`ofp_flow_stats`结构体用于表示流表统计信息,如流表项长度、优先级、数据包计数等。`ofp_port_stats`结构体用于表示端口统计信息,如端口号、接收数据包数、发送数据包数等。 ] == 消息头构建 #para[ 在OpenFlow协议中,每个消息都有一个消息头,用于标识消息的版本、类型、长度和事务ID。代码中实现了`build_opfmsg_header`函数,用于构建OpenFlow消息头。该函数接收消息长度、消息类型和事务ID作为参数,并填充消息头的各个字段。通过调用该函数,可以确保消息能够被正确解析和处理。 ] == 消息处理函数 #para[ 代码中实现了多个OpenFlow消息处理函数,每个函数对应一种OpenFlow消息类型。以下是每个函数的详细分析。 ] === 处理Hello消息 #para[ `handle_opfmsg_hello`函数用于处理控制器发送的Hello消息。Hello消息是OpenFlow协议中的基础消息,用于交换控制器和交换机之间的协议版本信息。函数首先检查消息头中的`version`字段,判断协议版本是否为1.3。如果版本匹配,则打印接收到的Hello消息;否则,生成一个错误消息并发送给控制器。函数返回`HANDLE`表示消息已处理。 ] ```c static enum ofperr handle_opfmsg_hello(struct ofp_buffer *ofpbuf) { if (ofpbuf->header.version == 0x04) { printf("RECV HELLO!\n\n\n"); } else { struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_ERROR, ofpbuf->header.xid, sizeof(struct ofp_header)); send_openflow_message(ofpbuf_reply, sizeof(struct ofp_header)); } return HANDLE; } ``` === 处理Features Request消息 #para[ `handle_opfmsg_features_request`函数用于处理控制器发送的Features Request消息。该消息用于查询交换机的特性信息,如支持的流表数量、缓冲区大小等。函数生成一个Features Reply消息,并填充交换机的特性信息,如数据路径ID、缓冲区数量、流表数量等。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。 ] ```c static enum ofperr handle_opfmsg_features_request(struct ofp_buffer *ofpbuf) { int feature_reply_len = sizeof(struct ofp_switch_features) + sizeof(struct ofp_header); struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_opfmsg_reply_ofpbuf(OFPT_FEATURES_REPLY, ofpbuf->header.xid, feature_reply_len); struct ofp_switch_features *feature_reply_msg = (struct ofp_switch_features *)ofpbuf_reply->data; feature_reply_msg->datapath_id = 0x0100000000000000; feature_reply_msg->n_buffers = htonl(46); feature_reply_msg->n_tables = 3; feature_reply_msg->capabilities = 0x7; send_openflow_message(ofpbuf_reply, feature_reply_len); return HANDLE; } ``` === 处理Get Config Request消息 #para[ `handle_ofpmsg_get_config_request`函数用于处理控制器发送的Get Config Request消息。该消息用于查询交换机的配置信息,如Miss Send Length等。函数生成一个Get Config Reply消息,并填充交换机的配置信息。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。 ] ```c static enum ofperr handle_ofpmsg_get_config_request(struct ofp_buffer *ofpbuf) { int reply_len = sizeof(struct ofp_switch_config) + sizeof(struct ofp_header); struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_GET_CONFIG_REPLY, ofpbuf->header.xid, reply_len); struct ofp_switch_config *switch_config_reply = (struct ofp_switch_config *)ofpbuf_reply->data; switch_config_reply->flags = htons(0x0000); switch_config_reply->miss_send_len = htons(32); send_openflow_message(ofpbuf_reply, reply_len); return HANDLE; } ``` === 处理Description Request消息 #para[ `handle_ofpmsg_desc`函数用于处理控制器发送的Description Request消息。该消息用于查询交换机的描述信息,如制造商、硬件版本等。函数生成一个Multipart Reply消息,并填充交换机的描述信息。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。 ] ```c static enum ofperr handle_ofpmsg_desc(struct ofp_buffer *ofpbuf) { int reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart) + sizeof(struct ofp_desc_stats); struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY, ofpbuf->header.xid, reply_len); struct ofp_multipart *ofpmp_reply = (struct ofp_multipart *)ofpbuf_reply->data; static const char *default_mfr_desc = "Wanglixuan"; static const char *default_hw_desc = "Lixuan_OpenBox"; static const char *default_sw_desc = "Lixuan_Driver"; static const char *default_serial_desc = "Lixuan OpenBox Series"; static const char *default_dp_desc = "None"; ofpmp_reply->type = htons(OFPMP_DESC); ofpmp_reply->flags = htonl(OFPMP_REPLY_MORE_NO); snprintf(ofpmp_reply->ofpmp_desc[0].mfr_desc, sizeof ofpmp_reply->ofpmp_desc[0].mfr_desc, "%s", default_mfr_desc); snprintf(ofpmp_reply->ofpmp_desc[0].hw_desc, sizeof ofpmp_reply->ofpmp_desc[0].hw_desc, "%s", default_hw_desc); snprintf(ofpmp_reply->ofpmp_desc[0].sw_desc, sizeof ofpmp_reply->ofpmp_desc[0].sw_desc, "%s", default_sw_desc); snprintf(ofpmp_reply->ofpmp_desc[0].serial_num, sizeof ofpmp_reply->ofpmp_desc[0].serial_num, "%s", default_serial_desc); snprintf(ofpmp_reply->ofpmp_desc[0].dp_desc, sizeof ofpmp_reply->ofpmp_desc[0].dp_desc, "%s", default_dp_desc); send_openflow_message(ofpbuf_reply, reply_len); return HANDLE; } ``` === 处理Flow Stats Request消息 #para[ `handle_ofpmsg_flow_stats`函数用于处理控制器发送的Flow Stats Request消息。该消息用于查询交换机的流表统计信息。函数生成一个Multipart Reply消息,并设置消息类型为Flow Stats。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。 ] ```c static enum ofperr handle_ofpmsg_flow_stats(struct ofp_buffer *ofpbuf) { int reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart); struct ofp_buffer *reply_buffer = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY, ofpbuf->header.xid, reply_len); struct ofp_multipart *multipart_reply = (struct ofp_multipart *)reply_buffer->data; multipart_reply->type = htons(OFPMP_FLOW); multipart_reply->flags = htonl(OFPMP_REPLY_MORE_NO); send_openflow_message(reply_buffer, reply_len); return HANDLE; } ``` // === 处理Aggregate Stats Request消息 // #para[ // `handle_ofpmsg_aggregate`函数用于处理控制器发送的Aggregate Stats Request消息。该消息用于查询交换机的聚合统计信息。函数生成一个Multipart Reply消息,并填充聚合统计信息,如数据包计数、字节计数等。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。 // ] // ```c // static enum ofperr handle_ofpmsg_aggregate(struct ofp_buffer *ofpbuf) { // int reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart) + sizeof(struct ofp_aggregate_stats_reply); // struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY, ofpbuf->header.xid, reply_len); // struct ofp_multipart *ofpmp_reply = (struct ofp_multipart *)ofpbuf_reply->data; // ofpmp_reply->type = htons(OFPMP_AGGREGATE); // ofpmp_reply->flags = htonl(OFPMP_REPLY_MORE_NO); // ofpmp_reply->ofpmp_aggregate_reply[0].packet_count = htonll(46); // ofpmp_reply->ofpmp_aggregate_reply[0].byte_count = htonll(2025); // ofpmp_reply->ofpmp_aggregate_reply[0].flow_count = htonll(200); // send_openflow_message(ofpbuf_reply, reply_len); // return HANDLE; // } // ``` === 处理Table Stats Request消息 #para[ `handle_ofpmsg_table`函数用于处理控制器发送的Table Stats Request消息。该消息用于查询交换机的流表统计信息。函数生成一个Multipart Reply消息,并填充流表统计信息,如匹配计数、查找计数等。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。 ] ```c static enum ofperr handle_ofpmsg_table(struct ofp_buffer *ofpbuf) { int reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart) + sizeof(struct ofp_table_stats) * 1; struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY, ofpbuf->header.xid, reply_len); struct ofp_multipart *ofpmp_reply = (struct ofp_multipart *)ofpbuf_reply->data; ofpmp_reply->type = htons(OFPMP_TABLE); ofpmp_reply->flags = htonl(OFPMP_REPLY_MORE_NO); ofpmp_reply->table_stats[0].matched_count = htonll(2025); ofpmp_reply->table_stats[0].table_id = 0; ofpmp_reply->table_stats[0].lookup_count = htonll(46); ofpmp_reply->table_stats[0].active_count = htonl(1); send_openflow_message(ofpbuf_reply, reply_len); return HANDLE; } ``` === 处理Port Stats Request消息 #para[ `handle_ofpmsg_port_stats`函数用于处理控制器发送的Port Stats Request消息。该消息用于查询交换机的端口统计信息。函数生成一个Multipart Reply消息,并填充端口统计信息,如持续时间、接收数据包数等。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。 ] ```c static enum ofperr handle_ofpmsg_port_stats(struct ofp_buffer *ofpbuf) { int reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart) + sizeof(struct ofp_port_stats) * nmps.cnt; struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY, ofpbuf->header.xid, reply_len); struct ofp_multipart *ofpmp_reply = (struct ofp_multipart *)ofpbuf_reply->data; ofpmp_reply->type = htons(OFPMP_PORT_STATS); ofpmp_reply->flags = htonl(OFPMP_REPLY_MORE_NO); for (int i = 0; i < nmps.cnt; i++) { ofpmp_reply->ofpmp_port_stats[i] = nmps.ports[i].stats; ofpmp_reply->ofpmp_port_stats[i].duration_sec = htonl(2025); ofpmp_reply->ofpmp_port_stats[i].duration_nsec = htonl(51); } send_openflow_message(ofpbuf_reply, reply_len); return HANDLE; } ``` === 处理Group Features Request消息 #para[ `handle_ofpmsg_group_features`函数用于处理控制器发送的Group Features Request消息。该消息用于查询交换机的组表特性信息。函数生成一个Multipart Reply消息,并填充组表特性信息,如最大组数等。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。 ] ```c static enum ofperr handle_ofpmsg_group_features(struct ofp_buffer *ofpbuf) { int reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_group_features) + 8; struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY, ofpbuf->header.xid, reply_len); struct ofp_group_features *group = (struct ofp_group_features *)ofpbuf_reply->data; group->types = htons(OFPMP_GROUP_FEATURES); group->max_groups[0] = htonl(0xdeadbeef); send_openflow_message(ofpbuf_reply, reply_len); return HANDLE; } ``` === 处理Port Description Request消息 #para[ `handle_ofpmsg_port_desc`函数用于处理控制器发送的Port Description Request消息。该消息用于查询交换机的端口描述信息。函数生成一个Multipart Reply消息,并填充端口描述信息,如端口状态等。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。 ] ```c static enum ofperr handle_ofpmsg_port_desc(struct ofp_buffer *ofpbuf) { int reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_multipart) + sizeof(struct ofp_port) * nmps.cnt; struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_MULTIPART_REPLY, ofpbuf->header.xid, reply_len); struct ofp_multipart *ofpmp_reply = (struct ofp_multipart *)ofpbuf_reply->data; ofpmp_reply->type = htons(OFPMP_PORT_DESC); ofpmp_reply->flags = htonl(OFPMP_REPLY_MORE_NO); for (int i = 0; i < nmps.cnt; i++) { ofpmp_reply->ofpmp_port_desc[i] = nmps.ports[i].state; } send_openflow_message(ofpbuf_reply, reply_len); return HANDLE; } ``` === 处理Packet Out消息 #para[ `handle_ofpmsg_packet_out`函数用于处理控制器发送的Packet Out消息。该消息用于指示交换机将数据包从指定端口发送出去。函数解析消息中的动作列表,判断动作类型是否为`OFPAT_OUTPUT`,并根据动作指示的端口号调用`nms_exec_action`函数将数据包发送出去。函数返回`HANDLE`表示消息已处理。 ] ```c static enum ofperr handle_ofpmsg_packet_out(struct ofp_buffer *ofpbuf) { struct ofp_packet_out *out = (struct ofp_packet_out *)ofpbuf; struct ofp_action_output *action = (struct ofp_action_output *)&out->actions[0]; int action_len = ntohs(out->actions_len); struct eth_header *eth = (struct eth_header *)&ofpbuf->data[sizeof(struct ofp_packet_out) - sizeof(struct ofp_header) + action_len]; int send_len = ntohs(ofpbuf->header.length) - sizeof(struct ofp_packet_out) - action_len; if (action_len == 0) { nms_exec_action(ntohl(out->in_port), OFPP_FLOOD, eth, send_len, -1); } else { while (action_len > 0) { if (action->type == OFPAT_OUTPUT) { nms_exec_action(ntohl(out->in_port), ntohl(action->port), eth, send_len, -1); } action_len -= sizeof(struct ofp_action_output); action++; } } return HANDLE; } ``` === 处理Role Request消息 #para[ `handle_opfmsg_role_request`函数用于处理控制器发送的Role Request消息。该消息用于配置交换机的角色(如主控制器、从控制器等)。函数生成一个Role Reply消息,并填充角色配置信息。通过`send_openflow_message`函数将回复消息发送给控制器,并返回`HANDLE`表示消息已处理。 ] ```c static enum ofperr handle_opfmsg_role_request(struct ofp_buffer *ofpbuf) { int reply_len = sizeof(struct ofp_header) + sizeof(struct ofp_role); struct ofp_buffer *ofpbuf_reply = (struct ofp_buffer *)build_reply_ofpbuf(OFPT_ROLE_REPLY, ofpbuf->header.xid, reply_len); memcpy(ofpbuf_reply->data, ofpbuf->data, sizeof(struct ofp_role)); ofpbuf_reply->header.type = OFPT_ROLE_REPLY; send_openflow_message(ofpbuf_reply, reply_len); return HANDLE; } ``` #pagebreak() == 实验结果 #para[ 在控制器与交换机之间进行抓包,分析报文的交互过程。控制器发送不同类型的OpenFlow消息给交换机,交换机接收并处理消息,并返回相应的回复消息。通过抓包分析,可以看到消息的交互过程,包括消息头、消息类型、消息长度等字段的解析和处理。用这种方式来验证协议编写的正确性。 ] #para[ 实现的子协议种类较多,这里只展示部分报文内容。 ] === OFPT_ROLE_REPLY #para[ OFPT_ROLE_REPLY类型消息。此消息用于配置交换机的角色(如主控制器、从控制器等)。下面的@slave_request 是控制器发送的Role Request消息。 ] #figure(image("master.png",fit:"stretch",format:"png"),caption:"OFPT_ROLE_REQUEST消息",) #para[ 如图@slave_reply 所示,交换机接收并处理后返回的Role Reply消息。 ] #figure(image("master_reply.png",fit:"stretch",format:"png"),caption:"OFPT_ROLE_REPLY消息",) #para[ 这说明交换机已经接收到了控制器发送的Role Request消息,并返回了Role Reply消息。 ] === OFPT_MULTIPART_REPLY #para[ OFPMP_DESC类型消息。此消息用于查询交换机的描述信息,包括制造商、硬件版本、软件版本、序列号和数据路径描述等。 ] #figure(image("cjy.png",fit:"stretch",format:"png"),caption:"OFPMP_DESC消息",) #para[ 可以看到图中的消息包含了制造商、硬件版本、软件版本、序列号和数据路径描述等信息(此处使用了自己的信息进行标记与区分)。 ] #para[ OFPMP_TABLE类型消息。此消息用于查询交换机的流表统计信息,包括匹配计数、查找计数等。 ] #figure(image("cjytable.png",fit:"stretch",format:"png"),caption:"OFPMP_TABLE消息",) #para[ 可以看到图中的消息包含了匹配计数、查找计数等信息(此处修改为了自己设置的值)。 ] #pagebreak() = 实验总结 #para[ 本次实验通过编写SDN交换机源码处理OpenFlow协议消息,深入理解了OpenFlow协议的基本消息格式和处理流程。实验涵盖了从交换机特性查询到流表统计、端口统计等多种消息类型的处理,成功实现了大部分OpenFlow协议的核心功能。通过实验,我不仅掌握了OpenFlow协议的基本工作原理,还熟悉了如何通过代码实现协议消息的解析与响应。 ] #para[ 在实验过程中,我首先熟悉了Openbox-S4的基本功能,并通过编写代码实现了对OpenFlow协议消息的处理。实验代码中,我实现了包括Hello消息、Features Request消息、Flow Stats Request消息等在内的多种消息处理函数。每个函数都根据消息类型生成相应的回复消息,并通过`send_openflow_message`函数发送给控制器。通过抓包分析,我验证了消息的交互过程,确保协议编写的正确性。 ] #para[ 实验中的难点在于如何正确处理不同类型的OpenFlow消息,并确保消息的格式和内容符合协议规范。通过查阅OpenFlow协议规范和参考相关文献,我逐步解决了这些问题,并成功实现了协议的核心功能。 ] #para[ 实验结果表明,我编写的代码能够正确处理控制器发送的OpenFlow消息,并返回相应的回复消息。通过抓包分析,我验证了消息的交互过程,确保协议编写的正确性。实验的成功不仅加深了我对OpenFlow协议的理解,也提升了我的编程能力和网络协议分析能力。 ] #para[ 总的来说,本次实验达到了预期的目标,成功实现了OpenFlow协议的核心功能。通过实验,我不仅掌握了OpenFlow协议的基本工作原理,还熟悉了如何通过代码实现协议消息的解析与响应。未来,我可以在此基础上进一步扩展功能,如实现流表规则的动态添加和删除,以更好地支持SDN网络的灵活性和可扩展性。 ] #pagebreak() = 选做实验介绍 #para[ 本小组了解了虚拟网络拓扑实验和DDoS网络攻击的SDN实验的基本内容,但由于时间和精力有限,最终选择只完成DDoS网络攻击的SDN实验。以下是对该实验的简要介绍。 ] == 实验原理 #para[本实验通过搭建一个基于 SDN 的网络环境,利用 OpenBox-S4 设备启动 OVS 交换机、sFlow-RT 流量监控和 Floodlight 控制器,模拟 DDoS 攻击并实现防御。实验的核心原理是通过 SDN 控制器(Floodlight)动态下发流表规则,检测并阻断异常流量。] #para[在实验中,主机 A 作为攻击者,使用 DDoS 攻击工具向主机 B(靶机)发送大量请求数据包,模拟 DDoS 攻击。sFlow-RT 用于实时监控网络流量,检测异常流量模式。Floodlight 控制器根据 sFlow-RT 的检测结果,下发流表规则到 OVS 交换机,丢弃匹配的异常流量,从而实现对 DDoS 攻击的防御。] #para[实验的关键在于通过 SDN 控制器的集中控制能力,动态调整网络流表,快速响应并阻断攻击流量。这种基于 SDN 的防御机制能够有效应对 DDoS 攻击,减少对网络资源的消耗,并提高网络的整体安全性。] #para[ 实验步骤参考《SDN网络-DDOS攻击案例操作手册.pdf》。下面仅列出部分步骤或结果,供参考。 ] === 发起 DDoS 攻击 #para[ 1.在主机 A 上使用攻击工具或脚本发起 DDoS 攻击,向主机 B 发送大量请求数据包。 2.监控 sFlow-RT 界面,观察网络流量的变化,检测到异常流量模式。 ] #figure(image("遭受DDoS攻击.png",format:"png",width: 100%,fit:"stretch"),caption: "遭受 DDoS 攻击") #para[ 3.记录攻击开始时间和网络状态。 4.查看流表项,发现大量异常流量匹配规则。 ] #figure(image("flow_entry.png",format:"png",width: 100%,fit:"stretch"),caption: "流表项") === 防御 DDoS 攻击 #para[ 1.使用 Floodlight 控制器下发流表规则,阻断异常流量: ] ```python import httplib import json class StaticFlowPusher(object): def __init__(self, server): self.server = server def get(self, data): ret = self.rest_call({}, 'GET') return json.loads(ret[2]) def set(self, data): ret = self.rest_call(data, 'POST') return ret[0] == 200 def remove(self, objtype, data): ret = self.rest_call(data, 'DELETE') return ret[0] == 200 def rest_call(self, data, action): path = '/wm/staticflowpusher/json' headers = { 'Content-type': 'application/json', 'Accept': 'application/json', } ``` ```python body = json.dumps(data) conn = httplib.HTTPConnection(self.server, 8080) conn.request(action, path, body, headers) response = conn.getresponse() ret = (response.status, response.reason, response.read()) print ret conn.close() return ret pusher = StaticFlowPusher('127.0.0.1') flowbe2 = { 'switch': "00:00:00:0a:35:00:5f:68", "name": "flow-2", "cookie": "G0", "priority": "100", "active": "true", "eth_type": "0x800", "in_port": "0", "ipv4_src": "192.168.2.111", "ipv4_dst": "192.168.2.119", "actions": "drop" } pusher.set(flowbe2) ``` #para[ 其中关键部分在于下发流表规则,将匹配的数据包丢弃(```python "actions": "drop"```)。 2.检查流量图,发现异常流量被丢弃。 ] #figure(image("防御DDoS攻击.png",format:"png",width: 100%,fit:"stretch"),caption: "丢弃异常流量") #para[ 3.检查流表项,发现异常流量匹配规则消失。 ] #figure(image("flow_entry2.png",format:"png",width: 100%,fit:"stretch"),caption: "流表项") == 选做实验总结 #para[ 本次实验通过搭建基于 OpenBox-S4 设备的 SDN 网络环境,模拟 DDoS 攻击和防御过程。通过实验,我了解了 sFlow-RT 的配置和使用方法,掌握了基于 Floodlight 控制器的 DDoS 防御原理和方法。实验中,我成功模拟了 DDoS 攻击,观察了网络流量的变化,学会了使用 Floodlight 控制器下发流表规则,阻断异常流量。通过实验,我深入理解了 SDN 网络中 DDoS 攻击的特点和防御策略,提高了网络安全意识和实践能力。 ] #pagebreak() #show heading: it => box(width: 100%)[ #v(0.50em) #set text(font: hei) // #counter(heading).display() // #h(0.5em) #it.body ] #bibliography("ref.yml",full: true,title: "参考文献",style:"gb-7714-2015-numeric") /* 根据这个网站的格式示范https://github.com/typst/hayagriva/blob/main/docs/file-format.md 为这些网页生成.yml文件 https://opennetworking.org/wp-content/uploads/2014/10/openflow-spec-v1.3.0.pdf https://www.cnblogs.com/goldsunshine/p/7262484.html https://www.jianshu.com/p/acfeae1771b3 https://www.jianshu.com/p/82e238eb8d14 */