Browse Source

ss-redir: allow you to define additionals listenings ports to set a TOS/DSCP on the outgoings ciphered connections

pull/1341/head
Martin Wetterwald 7 years ago
committed by Max Lv
parent
commit
6e069c7edb
4 changed files with 128 additions and 32 deletions
  1. 52
      src/jconf.c
  2. 17
      src/jconf.h
  3. 90
      src/redir.c
  4. 1
      src/redir.h

52
src/jconf.c

@ -109,6 +109,41 @@ parse_addr(const char *str_in, ss_addr_t *addr)
free(str);
}
static int
parse_dscp(char *str)
{
size_t str_len = strlen(str);
// Pre-defined values (EF, CSx, AFxy)
if (str_len == 2 && strcasecmp(str, "EF") == 0) {
return DSCP_EF;
}
if (str_len == DSCP_CS_LEN && strncasecmp(str, "CS", 2) == 0) {
if (str[2] >= '0' && str[2] <= '7') {
// CSx = 8x
return (str[2] - '0') << 3;
}
}
if (str_len == DSCP_AF_LEN && strncasecmp(str, "AF", 2) == 0) {
if (str[2] >= '1' && str[2] <= '4' && str[3] >= '1' && str[3] <= '3') {
// AFxy = 8x + 2y
return ((str[2] - '0') << 3) | ((str[3] - '0') << 1);
}
}
// Manual hexadecimal mode (0xYZ)
char *endptr;
int dscp = (int)strtol(str, &endptr, 0);
if (*endptr == '\0' && dscp >= DSCP_MIN && dscp <= DSCP_MAX) {
return dscp;
}
LOGE("Invalid DSCP value (%s)", str);
return DSCP_DEFAULT;
}
jconf_t *
read_jconf(const char *file)
{
@ -230,6 +265,23 @@ read_jconf(const char *file)
conf.nofile = value->u.integer;
} else if (strcmp(name, "nameserver") == 0) {
conf.nameserver = to_string(value);
} else if (strcmp(name, "dscp") == 0) {
if (value->type == json_object) {
for (j = 0; j < value->u.object.length; j++) {
if (j >= MAX_DSCP_NUM) {
break;
}
json_value *v = value->u.object.values[j].value;
if (v->type == json_string) {
int dscp = parse_dscp(to_string(v));
char *port = ss_strndup(value->u.object.values[j].name,
value->u.object.values[j].name_length);
conf.dscp[j].port = port;
conf.dscp[j].dscp = dscp;
conf.dscp_num = j + 1;
}
}
}
} else if (strcmp(name, "tunnel_address") == 0) {
conf.tunnel_address = to_string(value);
} else if (strcmp(name, "mode") == 0) {

17
src/jconf.h

@ -24,12 +24,22 @@
#define MAX_PORT_NUM 1024
#define MAX_REMOTE_NUM 10
#define MAX_DSCP_NUM 64
#define MAX_CONF_SIZE 128 * 1024
#define MAX_DNS_NUM 4
#define MAX_CONNECT_TIMEOUT 10
#define MAX_REQUEST_TIMEOUT 60
#define MIN_UDP_TIMEOUT 10
#define DSCP_EF 0x2E
#define DSCP_MIN 0x0
#define DSCP_MAX 0x3F
#define DSCP_DEFAULT 0x0
#define DSCP_MIN_LEN 2
#define DSCP_MAX_LEN 4
#define DSCP_CS_LEN 3
#define DSCP_AF_LEN 4
#define TCP_ONLY 0
#define TCP_AND_UDP 1
#define UDP_ONLY 3
@ -44,6 +54,11 @@ typedef struct {
char *password;
} ss_port_password_t;
typedef struct {
char *port;
int dscp;
} ss_dscp_t;
typedef struct {
int remote_num;
ss_addr_t remote_addr[MAX_REMOTE_NUM];
@ -63,6 +78,8 @@ typedef struct {
int reuse_port;
int nofile;
char *nameserver;
int dscp_num;
ss_dscp_t dscp[MAX_DSCP_NUM];
char *tunnel_address;
int mode;
int mtu;

90
src/redir.c

@ -786,6 +786,12 @@ accept_cb(EV_P_ ev_io *w, int revents)
// Set non blocking
setnonblocking(remotefd);
if (listener->tos >= 0) {
if (setsockopt(remotefd, IPPROTO_IP, IP_TOS, &listener->tos, sizeof(listener->tos)) != 0) {
ERROR("setsockopt IP_TOS");
}
}
// Enable MPTCP
if (listener->mptcp > 1) {
int err = setsockopt(remotefd, SOL_TCP, listener->mptcp, &opt, sizeof(opt));
@ -883,6 +889,9 @@ main(int argc, char **argv)
ss_addr_t remote_addr[MAX_REMOTE_NUM];
char *remote_port = NULL;
int dscp_num = 0;
ss_dscp_t * dscp = NULL;
static struct option long_options[] = {
{ "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN },
{ "mtu", required_argument, NULL, GETOPT_VAL_MTU },
@ -1061,6 +1070,8 @@ main(int argc, char **argv)
nofile = conf->nofile;
}
#endif
dscp_num = conf->dscp_num;
dscp = conf->dscp;
}
if (remote_num == 0 || remote_port == NULL || local_port == NULL
@ -1187,44 +1198,59 @@ main(int argc, char **argv)
struct ev_loop *loop = EV_DEFAULT;
if (mode != UDP_ONLY) {
// Setup socket
int listenfd;
listenfd = create_and_bind(local_addr, local_port);
if (listenfd == -1) {
FATAL("bind() error");
}
if (listen(listenfd, SOMAXCONN) == -1) {
FATAL("listen() error");
}
setnonblocking(listenfd);
listen_ctx_t* listen_ctx_current = &listen_ctx;
do {
if (mode != UDP_ONLY) {
// Setup socket
int listenfd;
listenfd = create_and_bind(local_addr, local_port);
if (listenfd == -1) {
FATAL("bind() error");
}
if (listen(listenfd, SOMAXCONN) == -1) {
FATAL("listen() error");
}
setnonblocking(listenfd);
listen_ctx.fd = listenfd;
listen_ctx_current->fd = listenfd;
ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx.io);
}
ev_io_init(&listen_ctx_current->io, accept_cb, listenfd, EV_READ);
ev_io_start(loop, &listen_ctx_current->io);
}
// Setup UDP
if (mode != TCP_ONLY) {
LOGI("UDP relay enabled");
char *host = remote_addr[0].host;
char *port = remote_addr[0].port == NULL ? remote_port : remote_addr[0].port;
struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage));
memset(storage, 0, sizeof(struct sockaddr_storage));
if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) {
FATAL("failed to resolve the provided hostname");
// Setup UDP
if (mode != TCP_ONLY) {
LOGI("UDP relay enabled");
char *host = remote_addr[0].host;
char *port = remote_addr[0].port == NULL ? remote_port : remote_addr[0].port;
struct sockaddr_storage *storage = ss_malloc(sizeof(struct sockaddr_storage));
memset(storage, 0, sizeof(struct sockaddr_storage));
if (get_sockaddr(host, port, storage, 1, ipv6first) == -1) {
FATAL("failed to resolve the provided hostname");
}
struct sockaddr *addr = (struct sockaddr *)storage;
init_udprelay(local_addr, local_port, addr,
get_sockaddr_len(addr), mtu, crypto, listen_ctx_current->timeout, NULL);
}
struct sockaddr *addr = (struct sockaddr *)storage;
init_udprelay(local_addr, local_port, addr,
get_sockaddr_len(addr), mtu, crypto, listen_ctx.timeout, NULL);
}
if (mode == UDP_ONLY) {
LOGI("TCP relay disabled");
}
if (mode == UDP_ONLY) {
LOGI("TCP relay disabled");
}
LOGI("listening at %s:%s", local_addr, local_port);
if(listen_ctx_current->tos) {
LOGI("listening at %s:%s (TOS/DSCP 0x%x)", local_addr, local_port, listen_ctx_current->tos);
} else {
LOGI("listening at %s:%s", local_addr, local_port);
}
// Handle additionals TOS/DSCP listening ports
if (dscp_num > 0) {
listen_ctx_current = (listen_ctx_t*) malloc(sizeof(listen_ctx_t));
listen_ctx_current = memcpy(listen_ctx_current, &listen_ctx, sizeof(listen_ctx_t));
local_port = dscp[dscp_num-1].port;
listen_ctx_current->tos = dscp[dscp_num-1].dscp;
}
} while (dscp_num-- > 0);
// setuid
if (user != NULL && !run_as(user)) {

1
src/redir.h

@ -37,6 +37,7 @@ typedef struct listen_ctx {
int timeout;
int fd;
int mptcp;
int tos;
struct sockaddr **remote_addr;
} listen_ctx_t;

Loading…
Cancel
Save