Skip to content

Commit

Permalink
feat: add udp support
Browse files Browse the repository at this point in the history
Signed-off-by: staylightblow8 <[email protected]>
  • Loading branch information
liudf0716 committed Aug 27, 2023
1 parent bd13b67 commit e5554ab
Show file tree
Hide file tree
Showing 9 changed files with 371 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ xfrpc
xfrp_test_server
bin
.vscode
build
35 changes: 29 additions & 6 deletions client.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,18 @@ is_socks5_proxy(const struct proxy_service *ps)
return 0;
}

int
is_udp_proxy (const struct proxy_service *ps)
{
if (! ps || ! ps->proxy_type)
return 0;

if (0 == strcmp(ps->proxy_type, "udp"))
return 1;

return 0;
}

// create frp tunnel for service
void
start_xfrp_tunnel(struct proxy_client *client)
Expand Down Expand Up @@ -151,14 +163,25 @@ start_xfrp_tunnel(struct proxy_client *client)
return;
}

// if client's proxy type is not socks5, then connect to local proxy server
if ( !is_socks5_proxy(client->ps) ) {
// if client's proxy type is udp
if ( is_udp_proxy(ps) ) {
debug(LOG_DEBUG, "start udp proxy tunnel for service [%s:%d]", ps->local_ip, ps->local_port);
client->local_proxy_bev = connect_udp_server(base);
if ( !client->local_proxy_bev ) {
debug(LOG_ERR, "frpc tunnel connect local proxy port [%d] failed!", ps->local_port);
del_proxy_client_by_stream_id(client->stream_id);
return;
}
} else if ( !is_socks5_proxy(ps) ) {
client->local_proxy_bev = connect_server(base, ps->local_ip, ps->local_port);
if ( !client->local_proxy_bev ) {
debug(LOG_ERR, "frpc tunnel connect local proxy port [%d] failed!", ps->local_port);
del_proxy_client_by_stream_id(client->stream_id);
return;
}
} else {
debug(LOG_DEBUG, "socks5 proxy client can't connect to remote server here ...");
return;
}

debug(LOG_DEBUG, "proxy server [%s:%d] <---> client [%s:%d]",
Expand All @@ -172,6 +195,9 @@ start_xfrp_tunnel(struct proxy_client *client)
if (PREDICT_FALSE(is_ftp_proxy(client->ps))) {
proxy_c2s_recv = ftp_proxy_c2s_cb;
proxy_s2c_recv = ftp_proxy_s2c_cb;
} else if ( is_udp_proxy(ps) ) {
proxy_c2s_recv = udp_proxy_c2s_cb;
proxy_s2c_recv = udp_proxy_s2c_cb;
} else {
proxy_c2s_recv = tcp_proxy_c2s_cb; // local service ---> xfrpc
proxy_s2c_recv = tcp_proxy_s2c_cb; // frps ---> xfrpc
Expand All @@ -186,10 +212,7 @@ start_xfrp_tunnel(struct proxy_client *client)
bufferevent_enable(client->ctl_bev, EV_READ|EV_WRITE);
}

if (is_socks5_proxy(client->ps)) {
debug(LOG_DEBUG, "socks5 proxy client can't connect to remote server here ...");
return;
}


bufferevent_setcb(client->local_proxy_bev,
proxy_c2s_recv,
Expand Down
4 changes: 3 additions & 1 deletion client.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ struct proxy_service {
int use_encryption;
int use_compression;

// tcp only
// tcp or udp
char *local_ip;
int remote_port;
int remote_data_port;
Expand Down Expand Up @@ -122,6 +122,8 @@ int is_ftp_proxy(const struct proxy_service *ps);

int is_socks5_proxy(const struct proxy_service *ps);

int is_udp_proxy(const struct proxy_service *ps);

struct proxy_client *new_proxy_client();

void clear_all_proxy_client();
Expand Down
44 changes: 44 additions & 0 deletions control.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "common.h"
#include "login.h"
#include "tcpmux.h"
#include "proxy.h"

static struct control *main_ctl;
static int client_connected = 0;
Expand Down Expand Up @@ -224,6 +225,33 @@ connect_server(struct event_base *base, const char *name, const int port)
return bev;
}

struct bufferevent *
connect_udp_server(struct event_base *base)
{
evutil_socket_t fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (fd < 0) {
debug(LOG_ERR, "create udp socket failed!");
return NULL;
}

if (evutil_make_socket_nonblocking(fd) < 0) {
debug(LOG_ERR, "make udp socket nonblocking failed!");
evutil_closesocket(fd);
return NULL;
}


struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
assert(bev);
if (!bev) {
evutil_closesocket(fd);
debug(LOG_ERR, "create udp bufferevent failed!");
return NULL;
}

return bev;
}

static void
set_ticker_ping_timer(struct event *timeout)
{
Expand Down Expand Up @@ -409,6 +437,22 @@ handle_control_work(const uint8_t *buf, int len, void *ctx)

break;
}
case TypeUDPPacket:
{
struct udp_packet *udp = udp_packet_unmarshal((const char *)msg->data);
if (!udp) {
debug(LOG_ERR, "TypeUDPPacket unmarshal failed!");
break;
}
debug(LOG_DEBUG, "recv udp packet from server, content is %s",
udp->content);
assert(ctx);
struct proxy_client *client = ctx;
assert(client->ps);
handle_udp_packet(udp, client);
SAFE_FREE(udp);
break;
}
case TypePong:
pong_time = time(NULL);
break;
Expand Down
2 changes: 2 additions & 0 deletions control.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,6 @@ void send_new_proxy(struct proxy_service *ps);

struct bufferevent *connect_server(struct event_base *base, const char *name, const int port);

struct bufferevent *connect_udp_server(struct event_base *base);

#endif //_CONTROL_H_
143 changes: 143 additions & 0 deletions msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,3 +427,146 @@ get_msg_type(uint8_t type)
return NULL;
}

// marshal udp packet msg
int
new_udp_packet_marshal(const struct udp_packet *udp, char **msg)
{
// parse struct udp_packet to json
struct json_object *j_udp = json_object_new_object();
assert(j_udp);

struct json_object *content = json_object_new_string(udp->content);
assert(content);
json_object_object_add(j_udp, "c", content);

if (udp->laddr) {
// laddr is a struct, parse it to json object and add to j_udp
struct json_object *j_laddr = json_object_new_object();
assert(j_laddr);
struct json_object *j_laddr_addr = json_object_new_string(udp->laddr->addr);
assert(j_laddr_addr);
json_object_object_add(j_laddr, "IP", j_laddr_addr);
struct json_object *j_laddr_port = json_object_new_int(udp->laddr->port);
assert(j_laddr_port);
json_object_object_add(j_laddr, "Port", j_laddr_port);
json_object_object_add(j_udp, "l", j_laddr);
json_object *j_laddr_zone = json_object_new_string("");
assert(j_laddr_zone);
json_object_object_add(j_laddr, "Zone", j_laddr_zone);
} else {
// laddr is NULL, add null to j_udp
struct json_object *j_laddr = json_object_new_object();
assert(j_laddr);
json_object_object_add(j_udp, "l", j_laddr);
}

if (udp->raddr) {
// raddr is a struct, parse it to json object and add to j_udp
struct json_object *j_raddr = json_object_new_object();
assert(j_raddr);
struct json_object *j_raddr_addr = json_object_new_string(udp->raddr->addr);
assert(j_raddr_addr);
json_object_object_add(j_raddr, "IP", j_raddr_addr);
struct json_object *j_raddr_port = json_object_new_int(udp->raddr->port);
assert(j_raddr_port);
json_object_object_add(j_raddr, "Port", j_raddr_port);
json_object_object_add(j_udp, "r", j_raddr);
json_object *j_raddr_zone = json_object_new_string("");
assert(j_raddr_zone);
json_object_object_add(j_raddr, "Zone", j_raddr_zone);
} else {
// raddr is NULL, add null to j_udp
struct json_object *j_raddr = json_object_new_object();
assert(j_raddr);
json_object_object_add(j_udp, "r", j_raddr);
}

// convert json to string msg
*msg = strdup(json_object_to_json_string(j_udp));
assert(*msg);
json_object_put(j_udp);

return 0;
}

void
udp_packet_free(struct udp_packet *udp)
{
if (!udp)
return;

SAFE_FREE(udp->content);
SAFE_FREE(udp->laddr->addr);
SAFE_FREE(udp->laddr->zone);
SAFE_FREE(udp->laddr);
SAFE_FREE(udp->raddr->addr);
SAFE_FREE(udp->raddr->zone);
SAFE_FREE(udp->raddr);

SAFE_FREE(udp);
}

// unmarshal udp packet msg
struct udp_packet *
udp_packet_unmarshal (const char *msg)
{
struct json_object *j_udp = json_tokener_parse(msg);
if (j_udp == NULL)
return NULL;
struct udp_packet *udp = calloc(sizeof(struct udp_packet), 1);
assert(udp);

struct json_object *j_content = NULL;
if(! json_object_object_get_ex(j_udp, "c", &j_content))
goto END_ERROR;
udp->content = strdup(json_object_get_string(j_content));
assert(udp->content);

struct json_object *j_laddr = NULL;
if(! json_object_object_get_ex(j_udp, "l", &j_laddr))
goto END_ERROR;
struct json_object *j_laddr_ip = NULL;
if(! json_object_object_get_ex(j_laddr, "IP", &j_laddr_ip))
goto END_ERROR;
struct json_object *j_laddr_port = NULL;
if(! json_object_object_get_ex(j_laddr, "Port", &j_laddr_port))
goto END_ERROR;
struct json_object *j_laddr_zone = NULL;
if(! json_object_object_get_ex(j_laddr, "Zone", &j_laddr_zone))
goto END_ERROR;
udp->laddr = calloc(sizeof(struct udp_addr), 1);
assert(udp->laddr);
udp->laddr->addr = strdup(json_object_get_string(j_laddr_ip));
assert(udp->laddr->addr);
udp->laddr->port = json_object_get_int(j_laddr_port);
udp->laddr->zone = strdup(json_object_get_string(j_laddr_zone));
assert(udp->laddr->zone);

struct json_object *j_raddr = NULL;
if(! json_object_object_get_ex(j_udp, "r", &j_raddr))
goto END_ERROR;
struct json_object *j_raddr_ip = NULL;
if(! json_object_object_get_ex(j_raddr, "IP", &j_raddr_ip))
goto END_ERROR;
struct json_object *j_raddr_port = NULL;
if(! json_object_object_get_ex(j_raddr, "Port", &j_raddr_port))
goto END_ERROR;
struct json_object *j_raddr_zone = NULL;
if(! json_object_object_get_ex(j_raddr, "Zone", &j_raddr_zone))
goto END_ERROR;
udp->raddr = calloc(sizeof(struct udp_addr), 1);
assert(udp->raddr);
udp->raddr->addr = strdup(json_object_get_string(j_raddr_ip));
assert(udp->raddr->addr);
udp->raddr->port = json_object_get_int(j_raddr_port);
udp->raddr->zone = strdup(json_object_get_string(j_raddr_zone));
assert(udp->raddr->zone);

json_object_put(j_udp);
return udp;

END_ERROR:
json_object_put(j_udp);
udp_packet_free(udp);
return NULL;
}
18 changes: 18 additions & 0 deletions msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ struct work_conn {
char *run_id;
};

struct upd_addr {
char *addr;
int port;
char *zone;
};

struct udp_packet {
char *content; // base64
struct upd_addr *laddr;
struct upd_addr *raddr;
};

struct __attribute__((__packed__)) msg_hdr {
char type;
uint64_t length;
Expand All @@ -96,6 +108,7 @@ struct start_work_conn_resp {
char *proxy_name;
};

int new_udp_packet_marshal(const struct udp_packet *udp, char **msg);
int new_proxy_service_marshal(const struct proxy_service *np_req, char **msg);
int msg_type_valid_check(char msg_type);
char *calc_md5(const char *data, int datalen);
Expand All @@ -112,6 +125,11 @@ struct control_response *control_response_unmarshal(const char *jres);
struct work_conn *new_work_conn();
int new_work_conn_marshal(const struct work_conn *work_c, char **msg);

// parse json string to udp packet
struct udp_packet *udp_packet_unmarshal(const char *jres);

void udp_packet_free(struct udp_packet *udp);

void control_response_free(struct control_response *res);

char *get_msg_type(uint8_t type);
Expand Down
5 changes: 5 additions & 0 deletions proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ void tcp_proxy_c2s_cb(struct bufferevent *bev, void *ctx);
void tcp_proxy_s2c_cb(struct bufferevent *bev, void *ctx);
void ftp_proxy_c2s_cb(struct bufferevent *bev, void *ctx);
void ftp_proxy_s2c_cb(struct bufferevent *bev, void *ctx);
void udp_proxy_c2s_cb(struct bufferevent *bev, void *ctx);
void udp_proxy_s2c_cb(struct bufferevent *bev, void *ctx);

struct proxy *new_proxy_obj(struct bufferevent *bev);
void free_proxy_obj(struct proxy *p);
void set_ftp_data_proxy_tunnel(const char *ftp_proxy_name,
Expand All @@ -65,4 +68,6 @@ void set_ftp_data_proxy_tunnel(const char *ftp_proxy_name,
uint32_t handle_socks5(struct proxy_client *client, struct ring_buffer *rb, int len);
uint32_t handle_ss5(struct proxy_client *client, struct ring_buffer *rb, int len);

void handle_udp_packet(struct udp_packet *udp_pkt, struct proxy_client *client);

#endif //_PROXY_H_
Loading

0 comments on commit e5554ab

Please sign in to comment.