Files
NE_YuR/openbox/openbox_1.typ
2025-11-21 11:53:09 +08:00

563 lines
28 KiB
Typst
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#import "labtemplate.typ": *
#show: nudtlabpaper.with(title: "SDN可编程网络实验",
author1: "程景愉",
id1: "202302723005",
advisor: " 胡罡",
jobtitle: "教授",
lab: "306-707",
date: "2025.1.2",
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消息",)<slave_request>
#para[
如图@slave_reply 所示交换机接收并处理后返回的Role Reply消息。
]
#figure(image("master_reply.png",fit:"stretch",format:"png"),caption:"OFPT_ROLE_REPLY消息",)<slave_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 攻击")<being_attacked_by_DDoS>
#para[
3.记录攻击开始时间和网络状态。
4.查看流表项,发现大量异常流量匹配规则。
]
#figure(image("flow_entry.png",format:"png",width: 100%,fit:"stretch"),caption: "流表项")<flow_table>
=== 防御 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: "丢弃异常流量")<defend_DDoS>
#para[
3.检查流表项,发现异常流量匹配规则消失。
]
#figure(image("flow_entry2.png",format:"png",width: 100%,fit:"stretch"),caption: "流表项")<flow_table_defend>
== 选做实验总结
#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
*/