Skip to content

Commit

Permalink
服务端支持配置多局域网组网
Browse files Browse the repository at this point in the history
  • Loading branch information
lanthora committed Jul 4, 2024
1 parent c7137cc commit c5e6c9c
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 4 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.18.4)

project(candy LANGUAGES C CXX VERSION 5.9.3)
project(candy LANGUAGES C CXX VERSION 5.9.4)

option(CANDY_NOEXE "Don't build executable")
option(CANDY_DEVEL "Build development library")
Expand Down
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,14 @@ dhcp = "10.0.0.0/24"
password = "123456"
```

配置[多局域网组网](docs/muti-lan-interconn.md)

```bash
# 进入设备网络 10.0.0.1/32 且目的网络为 192.168.2.0/24 的 IP 报文通过 10.0.0.2 转发,
# 通过分号分割的多条规则,配置中禁止出现空白符.
sdwan = "10.0.0.1/32,192.168.2.0/24,10.0.0.2;10.0.0.2/32,192.168.1.0/24,10.0.0.1";
```

#### 客户端

与上述服务端匹配的客户端配置
Expand All @@ -186,7 +194,7 @@ stun = "stun://stun.canets.org"
port = 0
```

关于路由的配置
配置客户端中继

```bash
# 路由功能在对等连接的基础上工作,对等连接是被动启动,
Expand All @@ -201,7 +209,7 @@ discovery = 300
route = 5
```

关于局域网内建立对等的配置
配置局域网内对等链接

```bash
# 用于建立对等连接的本机局域网 IP 地址,不配置此项时将尝试自动获取.
Expand Down
6 changes: 6 additions & 0 deletions candy.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ websocket = "wss://canets.org/demo";
# configure a static address through tun.
#dhcp = "172.16.0.0/16";

# [Optional] software-defined wide area network
# IP packets entering 172.16.0.1/32 with the destination address 192.168.2.0/24
# will be forwarded to 172.16.0.2. Multiple rules are separated by semicolons.
# Extraneous whitespace characters are prohibited.
#sdwan = "172.16.0.1/32,192.168.2.0/24,172.16.0.2;172.16.0.2/32,192.168.1.0/24,172.16.0.1";

################################# Client Only #################################
# [Optional] Network interface name
# Used to differentiate networks when running multiple clients.
Expand Down
2 changes: 1 addition & 1 deletion docs/muti-lan-interconn.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

此处假设你已经:

- 成功部署 Web 版本[服务端](https://hub.docker.com/r/lanthora/cucurbita)
- 成功部署服务端
- 在网关 (Gateway) 上部署 Candy 并分配了虚拟地址

以 LAN A 为例解释表格含义.
Expand Down
52 changes: 52 additions & 0 deletions src/core/server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <Poco/URI.h>
#include <spdlog/fmt/bin_to_hex.h>
#include <spdlog/spdlog.h>
#include <sstream>

namespace Candy {

Expand Down Expand Up @@ -47,6 +48,34 @@ int Server::setDynamicAddressRange(const std::string &cidr) {
return 0;
}

int Server::setSdwan(const std::string &sdwan) {
if (sdwan.empty()) {
return 0;
}
std::string route;
std::stringstream stream(sdwan);
while (std::getline(stream, route, ';')) {
std::string addr;
SysRoute rt;
std::stringstream ss(route);
if (!std::getline(ss, addr, ',') || rt.dev.cidrUpdate(addr) || rt.dev.getIp() != rt.dev.getNet()) {
spdlog::critical("invalid route device: {}", route);
return -1;
}
if (!std::getline(ss, addr, ',') || rt.dst.cidrUpdate(addr) || rt.dst.getIp() != rt.dst.getNet()) {
spdlog::critical("invalid route dest: {}", route);
return -1;
}
if (!std::getline(ss, addr, ',') || rt.next.ipStrUpdate(addr)) {
spdlog::critical("invalid route nexthop: {}", route);
return -1;
}
spdlog::info("route: dev={} dst={} next={}", rt.dev.getCidr(), rt.dst.getCidr(), rt.next.getIpStr());
this->routes.push_back(rt);
}
return 0;
}

int Server::run() {
this->running = true;
if (startWsThread()) {
Expand Down Expand Up @@ -180,6 +209,7 @@ void Server::handleAuthMessage(WebSocketMessage &message) {

this->ipWsMap[address.getIp()] = message.conn;
this->wsIpMap[message.conn] = address.getIp();
updateClientRoute(message, address.getIp());
}

void Server::handleForwardMessage(WebSocketMessage &message) {
Expand Down Expand Up @@ -468,4 +498,26 @@ void Server::handleCloseMessage(WebSocketMessage &message) {
this->wsMacMap.erase(message.conn);
}

void Server::updateClientRoute(WebSocketMessage &message, uint32_t client) {
message.buffer.resize(sizeof(SysRouteMessage));
SysRouteMessage *header = (SysRouteMessage *)message.buffer.data();
memset(header, 0, sizeof(SysRouteMessage));
header->type = MessageType::ROUTE;

for (auto rt : this->routes) {
if ((rt.dev.getMask() & client) == rt.dev.getIp()) {
SysRouteItem item;
item.dest = Address::hostToNet(rt.dst.getNet());
item.mask = Address::hostToNet(rt.dst.getMask());
item.nexthop = Address::hostToNet(rt.next.getIp());
message.buffer.append((char *)(&item), sizeof(item));
header->size += 1;
}
}

if (header->size > 0) {
this->ws.write(message);
}
}

} // namespace Candy
11 changes: 11 additions & 0 deletions src/core/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,25 @@

#include "utility/address.h"
#include "websocket/server.h"
#include <list>
#include <map>
#include <string>
#include <thread>

namespace Candy {

struct SysRoute {
Address dev;
Address dst;
Address next;
};

class Server {
public:
int setWebSocketServer(const std::string &uri);
int setPassword(const std::string &password);
int setDynamicAddressRange(const std::string &cidr);
int setSdwan(const std::string &sdwan);

int run();
int shutdown();
Expand All @@ -32,6 +40,8 @@ class Server {
void handleGeneralMessage(WebSocketMessage &message);
void handleCloseMessage(WebSocketMessage &message);

void updateClientRoute(WebSocketMessage &message, uint32_t client);

bool running = false;
uint16_t port;
std::string host;
Expand All @@ -45,6 +55,7 @@ class Server {
std::map<uint32_t, WebSocketConn> ipWsMap;
std::map<WebSocketConn, uint32_t> wsIpMap;
std::map<WebSocketConn, std::string> wsMacMap;
std::list<SysRoute> routes;
};

} // namespace Candy
Expand Down
5 changes: 5 additions & 0 deletions src/main/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct arguments {

// 服务端配置
std::string dhcp;
std::string sdwan;

// 客户端配置
std::string name;
Expand Down Expand Up @@ -82,6 +83,7 @@ void parseConfig(std::string cfgFile, arguments &args) {
{"debug", [&](const std::string &value) { args.debug = (value == "true"); }},
{"restart", [&](const std::string &value) { args.restart = std::stoi(value); }},
{"dhcp", [&](const std::string &value) { args.dhcp = value; }},
{"sdwan", [&](const std::string &value) { args.sdwan = value; }},
{"tun", [&](const std::string &value) { args.tun = value; }},
{"stun", [&](const std::string &value) { args.stun = value; }},
{"name", [&](const std::string &value) { args.name = value; }},
Expand Down Expand Up @@ -256,6 +258,7 @@ int serve(const arguments &args) {
server.setPassword(args.password);
server.setWebSocketServer(args.websocket);
server.setDynamicAddressRange(args.dhcp);
server.setSdwan(args.sdwan);
server.run();
}

Expand Down Expand Up @@ -299,6 +302,7 @@ int parseConfig(int argc, char *argv[], arguments &args) {
program.add_argument("-p", "--password").help("authorization password").metavar("TEXT");
program.add_argument("--restart").help("restart interval").scan<'i', int>().metavar("SECONDS");
program.add_argument("-d", "--dhcp").help("dhcp address range").metavar("CIDR");
program.add_argument("--sdwan").help("software-defined wide area network").metavar("ROUTES");
program.add_argument("-n", "--name").help("network interface name").metavar("TEXT");
program.add_argument("-t", "--tun").help("static address").metavar("CIDR");
program.add_argument("-s", "--stun").help("stun address").metavar("URI");
Expand All @@ -323,6 +327,7 @@ int parseConfig(int argc, char *argv[], arguments &args) {
args.noTimestamp = program.is_used("--no-timestamp") ? program.get<bool>("--no-timestamp") : args.noTimestamp;
args.debug = program.is_used("--debug") ? program.get<bool>("--debug") : args.debug;
args.dhcp = program.is_used("--dhcp") ? program.get<std::string>("--dhcp") : args.dhcp;
args.sdwan = program.is_used("--sdwan") ? program.get<std::string>("--sdwan") : args.sdwan;
args.name = program.is_used("--name") ? program.get<std::string>("--name") : args.name;
args.tun = program.is_used("--tun") ? program.get<std::string>("--tun") : args.tun;
args.stun = program.is_used("--stun") ? program.get<std::string>("--stun") : args.stun;
Expand Down

0 comments on commit c5e6c9c

Please sign in to comment.