mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-11-01 07:30:02 +00:00
add CRC8 for payload authentication
This commit is contained in:
@@ -1462,3 +1462,70 @@ int enc_init(const char *pass, const char *method)
|
||||
return m;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial. A table-based
|
||||
* algorithm would be faster, but for only a few bytes it isn't worth the code
|
||||
* size.
|
||||
*/
|
||||
uint8_t crc8(const void *vptr, int len)
|
||||
{
|
||||
const uint8_t *data = vptr;
|
||||
unsigned crc = 0;
|
||||
int i, j;
|
||||
|
||||
for (j = len; j; j--, data++) {
|
||||
crc ^= (*data << 8);
|
||||
for(i = 8; i; i--) {
|
||||
if (crc & 0x8000)
|
||||
crc ^= (0x1070 << 3);
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (uint8_t)(crc >> 8);
|
||||
}
|
||||
|
||||
int ss_check_crc(char *buf, ssize_t *buf_len, char *crc_buf, ssize_t *crc_idx)
|
||||
{
|
||||
int i, j;
|
||||
ssize_t blen = *buf_len;
|
||||
ssize_t cidx = *crc_idx;
|
||||
|
||||
for (i = 0, j = 0; i < blen; i++) {
|
||||
if (cidx == CRC_BUF_LEN) {
|
||||
uint8_t c = crc8((const void*)crc_buf, CRC_BUF_LEN);
|
||||
if (memcmp(&c, buf + i, 1) != 0) return 0;
|
||||
cidx = 0;
|
||||
} else {
|
||||
crc_buf[cidx] = buf[j] = buf[i];
|
||||
cidx++; j++;
|
||||
}
|
||||
}
|
||||
*buf_len = j;
|
||||
*crc_idx = cidx;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ss_gen_crc(char *buf, ssize_t *buf_len, char *crc_buf, ssize_t *crc_idx, int buf_size)
|
||||
{
|
||||
int i, j;
|
||||
ssize_t blen = *buf_len;
|
||||
ssize_t cidx = *crc_idx;
|
||||
int size = max(blen / CRC_BUF_LEN + blen, buf_size);
|
||||
|
||||
if (buf_size < size) {
|
||||
buf = realloc(buf, size);
|
||||
}
|
||||
for (i = 0, j = 0; i < blen; i++, j++) {
|
||||
if (cidx == CRC_BUF_LEN) {
|
||||
uint8_t c = crc8((const void*)crc_buf, CRC_BUF_LEN);
|
||||
memmove(buf + j + 1, buf + j, blen - i);
|
||||
memcpy(buf + j, &c, 1);
|
||||
j++; cidx = 0;
|
||||
}
|
||||
crc_buf[cidx] = buf[j];
|
||||
cidx++;
|
||||
}
|
||||
*buf_len = j;
|
||||
*crc_idx = cidx;
|
||||
}
|
||||
|
||||
@@ -147,6 +147,8 @@ typedef struct {
|
||||
#define ONETIMEAUTH_MASK 0xF0
|
||||
#define ADDRTYPE_MASK 0xF
|
||||
|
||||
#define CRC_BUF_LEN 128
|
||||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
@@ -171,4 +173,7 @@ unsigned char *enc_md5(const unsigned char *d, size_t n, unsigned char *md);
|
||||
int ss_onetimeauth(char *auth, char *msg, int msg_len);
|
||||
int ss_onetimeauth_verify(char *auth, char *msg, int msg_len);
|
||||
|
||||
int ss_check_crc(char *buf, ssize_t *buf_len, char *crc_buf, ssize_t *crc_idx);
|
||||
void ss_gen_crc(char *buf, ssize_t *buf_len, char *crc_buf, ssize_t *crc_idx, int buf_size);
|
||||
|
||||
#endif // _ENCRYPT_H
|
||||
|
||||
@@ -244,6 +244,10 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
return;
|
||||
}
|
||||
|
||||
if (remote->send_ctx->connected && auth) {
|
||||
ss_gen_crc(remote->buf, &r, remote->crc_buf, &remote->crc_idx, BUF_SIZE);
|
||||
}
|
||||
|
||||
// insert shadowsocks header
|
||||
if (!remote->direct) {
|
||||
remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r,
|
||||
@@ -478,6 +482,11 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
|
||||
memcpy(remote->buf, ss_addr_to_send, addr_len);
|
||||
|
||||
if (auth) {
|
||||
ss_gen_crc(buf, &r, remote->crc_buf, &remote->crc_idx, BUF_SIZE);
|
||||
}
|
||||
|
||||
if (r > 0) {
|
||||
memcpy(remote->buf + addr_len, buf, r);
|
||||
}
|
||||
|
||||
@@ -81,6 +81,9 @@ struct remote {
|
||||
struct server *server;
|
||||
struct sockaddr_storage addr;
|
||||
int addr_len;
|
||||
|
||||
ssize_t crc_idx;
|
||||
char crc_buf[CRC_BUF_LEN];
|
||||
};
|
||||
|
||||
#endif // _LOCAL_H
|
||||
|
||||
@@ -184,7 +184,12 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
}
|
||||
|
||||
if (auth) {
|
||||
ss_gen_crc(remote->buf, &r, remote->crc_buf, &remote->crc_idx, BUF_SIZE);
|
||||
}
|
||||
|
||||
remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r, server->e_ctx);
|
||||
|
||||
if (remote->buf == NULL) {
|
||||
LOGE("invalid password or cipher");
|
||||
close_and_free_remote(EV_A_ remote);
|
||||
@@ -193,6 +198,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
|
||||
int s = send(remote->fd, remote->buf, r, 0);
|
||||
|
||||
if (s == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
// no data, wait for send
|
||||
@@ -444,6 +450,9 @@ static struct remote * new_remote(int fd, int timeout)
|
||||
{
|
||||
struct remote *remote;
|
||||
remote = malloc(sizeof(struct remote));
|
||||
|
||||
memset(remote, 0, sizeof(struct remote));
|
||||
|
||||
remote->buf = malloc(BUF_SIZE);
|
||||
remote->recv_ctx = malloc(sizeof(struct remote_ctx));
|
||||
remote->send_ctx = malloc(sizeof(struct remote_ctx));
|
||||
|
||||
@@ -70,6 +70,9 @@ struct remote {
|
||||
struct remote_ctx *recv_ctx;
|
||||
struct remote_ctx *send_ctx;
|
||||
struct server *server;
|
||||
|
||||
ssize_t crc_idx;
|
||||
char crc_buf[CRC_BUF_LEN];
|
||||
};
|
||||
|
||||
#endif // _LOCAL_H
|
||||
|
||||
@@ -495,6 +495,14 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
|
||||
// handshake and transmit data
|
||||
if (server->stage == 5) {
|
||||
if (server->auth
|
||||
&& !ss_check_crc(remote->buf, &r, server->crc_buf, &server->crc_idx)) {
|
||||
LOGE("crc error");
|
||||
report_addr(server->fd);
|
||||
close_and_free_server(EV_A_ server);
|
||||
close_and_free_remote(EV_A_ remote);
|
||||
return;
|
||||
}
|
||||
int s = send(remote->fd, remote->buf, r, 0);
|
||||
if (s == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
@@ -648,6 +656,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
return;
|
||||
};
|
||||
offset += ONETIMEAUTH_BYTES;
|
||||
server->auth = 1;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
@@ -660,6 +669,14 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
server->buf_idx = offset;
|
||||
}
|
||||
|
||||
if (server->auth
|
||||
&& !ss_check_crc(server->buf + server->buf_idx, &server->buf_len, server->crc_buf, &server->crc_idx)) {
|
||||
LOGE("crc error");
|
||||
report_addr(server->fd);
|
||||
close_and_free_server(EV_A_ server);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!need_query) {
|
||||
struct remote *remote = connect_to_remote(&info, server);
|
||||
|
||||
@@ -1061,6 +1078,9 @@ static struct server * new_server(int fd, struct listen_ctx *listener)
|
||||
|
||||
struct server *server;
|
||||
server = malloc(sizeof(struct server));
|
||||
|
||||
memset(server, 0, sizeof(struct server));
|
||||
|
||||
server->buf = malloc(BUF_SIZE);
|
||||
server->recv_ctx = malloc(sizeof(struct server_ctx));
|
||||
server->send_ctx = malloc(sizeof(struct server_ctx));
|
||||
|
||||
@@ -55,6 +55,11 @@ struct server {
|
||||
ssize_t buf_len;
|
||||
ssize_t buf_idx;
|
||||
char *buf; // server send from, remote recv into
|
||||
|
||||
int auth;
|
||||
ssize_t crc_idx;
|
||||
char crc_buf[CRC_BUF_LEN];
|
||||
|
||||
struct enc_ctx *e_ctx;
|
||||
struct enc_ctx *d_ctx;
|
||||
struct server_ctx *recv_ctx;
|
||||
|
||||
@@ -196,6 +196,10 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
}
|
||||
|
||||
if (auth) {
|
||||
ss_gen_crc(remote->buf, &r, remote->crc_buf, &remote->crc_idx, BUF_SIZE);
|
||||
}
|
||||
|
||||
remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r, server->e_ctx);
|
||||
|
||||
if (remote->buf == NULL) {
|
||||
@@ -485,6 +489,9 @@ static struct remote * new_remote(int fd, int timeout)
|
||||
{
|
||||
struct remote *remote;
|
||||
remote = malloc(sizeof(struct remote));
|
||||
|
||||
memset(remote, 0, sizeof(struct remote));
|
||||
|
||||
remote->buf = malloc(BUF_SIZE);
|
||||
remote->recv_ctx = malloc(sizeof(struct remote_ctx));
|
||||
remote->send_ctx = malloc(sizeof(struct remote_ctx));
|
||||
|
||||
@@ -74,6 +74,9 @@ struct remote {
|
||||
struct remote_ctx *recv_ctx;
|
||||
struct remote_ctx *send_ctx;
|
||||
struct server *server;
|
||||
|
||||
ssize_t crc_idx;
|
||||
char crc_buf[CRC_BUF_LEN];
|
||||
};
|
||||
|
||||
#endif // _TUNNEL_H
|
||||
|
||||
Reference in New Issue
Block a user