|
|
@ -40,7 +40,7 @@ struct f2b_csock_t { |
|
|
|
int nlisten; |
|
|
|
int nlisten; |
|
|
|
int nclients; |
|
|
|
int nclients; |
|
|
|
char password[32]; |
|
|
|
char password[32]; |
|
|
|
}; |
|
|
|
} csock; |
|
|
|
|
|
|
|
|
|
|
|
/* helpers */ |
|
|
|
/* helpers */ |
|
|
|
|
|
|
|
|
|
|
@ -336,69 +336,64 @@ f2b_sock_destroy(f2b_sock_t *sock) { |
|
|
|
|
|
|
|
|
|
|
|
/* control socket-related functions */ |
|
|
|
/* control socket-related functions */ |
|
|
|
|
|
|
|
|
|
|
|
f2b_csock_t * |
|
|
|
bool |
|
|
|
f2b_csocket_create(f2b_config_section_t *config) { |
|
|
|
f2b_csocket_create(f2b_config_section_t *config) { |
|
|
|
f2b_csock_t *csock = NULL; |
|
|
|
|
|
|
|
f2b_sock_t *sock = NULL; |
|
|
|
f2b_sock_t *sock = NULL; |
|
|
|
bool need_pass = false; |
|
|
|
bool need_pass = false; |
|
|
|
|
|
|
|
|
|
|
|
if ((csock = calloc(1, sizeof(f2b_csock_t))) == NULL) { |
|
|
|
memset(&csock, 0x0, sizeof(csock)); |
|
|
|
f2b_log_msg(log_error, "can't allocate memory for csocket struct"); |
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (f2b_config_param_t *p = config->param; p != NULL; p = p->next) { |
|
|
|
for (f2b_config_param_t *p = config->param; p != NULL; p = p->next) { |
|
|
|
if (strcmp(p->name, "listen") == 0) { |
|
|
|
if (strcmp(p->name, "listen") == 0) { |
|
|
|
if (csock->nlisten >= CSOCKET_MAX_LISTEN) { |
|
|
|
if (csock.nlisten >= CSOCKET_MAX_LISTEN) { |
|
|
|
f2b_log_msg(log_error, "ignoring excess 'listen' directive: %s", p->value); |
|
|
|
f2b_log_msg(log_error, "ignoring excess 'listen' directive: %s", p->value); |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
if ((sock = f2b_sock_create(p->value)) != NULL) { |
|
|
|
if ((sock = f2b_sock_create(p->value)) != NULL) { |
|
|
|
csock->listen[csock->nlisten] = sock; |
|
|
|
csock.listen[csock.nlisten] = sock; |
|
|
|
csock->nlisten++; |
|
|
|
csock.nlisten++; |
|
|
|
if (strncmp(p->value, "inet:", 5) == 0) |
|
|
|
if (strncmp(p->value, "inet:", 5) == 0) |
|
|
|
need_pass = true; |
|
|
|
need_pass = true; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (strcmp(p->name, "password") == 0) { |
|
|
|
if (strcmp(p->name, "password") == 0) { |
|
|
|
strlcpy(csock->password, p->value, sizeof(csock->password)); |
|
|
|
strlcpy(csock.password, p->value, sizeof(csock.password)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (csock->nlisten == 0) { |
|
|
|
if (csock.nlisten == 0) { |
|
|
|
f2b_csocket_destroy(csock); |
|
|
|
f2b_csocket_destroy(); |
|
|
|
return NULL; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
if (need_pass && strcmp(csock->password, "") == 0) { |
|
|
|
if (need_pass && strcmp(csock.password, "") == 0) { |
|
|
|
snprintf(csock->password, sizeof(csock->password), "%lx+%ld", random(), time(NULL)); |
|
|
|
snprintf(csock.password, sizeof(csock.password), "%lx+%ld", random(), time(NULL)); |
|
|
|
f2b_log_msg(log_info, "set random password for control socket: %s", csock->password); |
|
|
|
f2b_log_msg(log_info, "set random password for control socket: %s", csock.password); |
|
|
|
} |
|
|
|
} |
|
|
|
return csock; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
void |
|
|
|
f2b_csocket_destroy(f2b_csock_t *csock) { |
|
|
|
f2b_csocket_destroy() { |
|
|
|
f2b_sock_t *sock = NULL; |
|
|
|
f2b_sock_t *sock = NULL; |
|
|
|
f2b_conn_t *conn = NULL; |
|
|
|
f2b_conn_t *conn = NULL; |
|
|
|
assert(csock != NULL); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < CSOCKET_MAX_LISTEN; i++) { |
|
|
|
for (int i = 0; i < CSOCKET_MAX_LISTEN; i++) { |
|
|
|
if ((sock = csock->listen[i]) == NULL) |
|
|
|
if ((sock = csock.listen[i]) == NULL) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
f2b_sock_destroy(csock->listen[i]); |
|
|
|
f2b_sock_destroy(csock.listen[i]); |
|
|
|
csock->listen[i] = NULL; |
|
|
|
csock.listen[i] = NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
for (int i = 0; i < CSOCKET_MAX_CLIENTS; i++) { |
|
|
|
for (int i = 0; i < CSOCKET_MAX_CLIENTS; i++) { |
|
|
|
if ((conn = csock->clients[i]) == NULL) |
|
|
|
if ((conn = csock.clients[i]) == NULL) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
f2b_conn_destroy(conn); |
|
|
|
f2b_conn_destroy(conn); |
|
|
|
csock->clients[i] = NULL; |
|
|
|
csock.clients[i] = NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
free(csock); |
|
|
|
memset(&csock, 0x0, sizeof(csock)); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
void |
|
|
|
f2b_csocket_poll(f2b_csock_t *csock, void (*cb)(const f2b_cmd_t *cmd, f2b_buf_t *res)) { |
|
|
|
f2b_csocket_poll(void (*cb)(const f2b_cmd_t *cmd, f2b_buf_t *res)) { |
|
|
|
struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; |
|
|
|
struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; |
|
|
|
fd_set rfds, wfds; |
|
|
|
fd_set rfds, wfds; |
|
|
|
f2b_conn_t *conn = NULL; |
|
|
|
f2b_conn_t *conn = NULL; |
|
|
@ -406,22 +401,21 @@ f2b_csocket_poll(f2b_csock_t *csock, void (*cb)(const f2b_cmd_t *cmd, f2b_buf_t |
|
|
|
struct sockaddr_storage addr; |
|
|
|
struct sockaddr_storage addr; |
|
|
|
socklen_t addrlen; |
|
|
|
socklen_t addrlen; |
|
|
|
|
|
|
|
|
|
|
|
assert(csock != NULL); |
|
|
|
|
|
|
|
assert(cb != NULL); |
|
|
|
assert(cb != NULL); |
|
|
|
|
|
|
|
|
|
|
|
/* loop / init */ |
|
|
|
/* loop / init */ |
|
|
|
FD_ZERO(&rfds); |
|
|
|
FD_ZERO(&rfds); |
|
|
|
FD_ZERO(&wfds); |
|
|
|
FD_ZERO(&wfds); |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < csock->nlisten; i++) { |
|
|
|
for (int i = 0; i < csock.nlisten; i++) { |
|
|
|
sock = csock->listen[i]->sock; |
|
|
|
sock = csock.listen[i]->sock; |
|
|
|
FD_SET(sock, &rfds); /* watch for new connections */ |
|
|
|
FD_SET(sock, &rfds); /* watch for new connections */ |
|
|
|
nfds = max(nfds, sock); |
|
|
|
nfds = max(nfds, sock); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* watch for new data on established connections */ |
|
|
|
/* watch for new data on established connections */ |
|
|
|
for (int cnum = 0; cnum < CSOCKET_MAX_CLIENTS; cnum++) { |
|
|
|
for (int cnum = 0; cnum < CSOCKET_MAX_CLIENTS; cnum++) { |
|
|
|
if ((conn = csock->clients[cnum]) == NULL) |
|
|
|
if ((conn = csock.clients[cnum]) == NULL) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
FD_SET(conn->sock, &rfds); |
|
|
|
FD_SET(conn->sock, &rfds); |
|
|
|
if (conn->send.used) |
|
|
|
if (conn->send.used) |
|
|
@ -445,23 +439,23 @@ f2b_csocket_poll(f2b_csock_t *csock, void (*cb)(const f2b_cmd_t *cmd, f2b_buf_t |
|
|
|
return; /* no new data */ |
|
|
|
return; /* no new data */ |
|
|
|
|
|
|
|
|
|
|
|
/* new connection on listening socket? */ |
|
|
|
/* new connection on listening socket? */ |
|
|
|
for (int i = 0; i < csock->nlisten; i++) { |
|
|
|
for (int i = 0; i < csock.nlisten; i++) { |
|
|
|
if (!FD_ISSET(csock->listen[i]->sock, &rfds)) |
|
|
|
if (!FD_ISSET(csock.listen[i]->sock, &rfds)) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
/* find free connection slot */ |
|
|
|
/* find free connection slot */ |
|
|
|
int cnum = 0; |
|
|
|
int cnum = 0; |
|
|
|
for (int cnum = 0; cnum < CSOCKET_MAX_CLIENTS; cnum++) { |
|
|
|
for (int cnum = 0; cnum < CSOCKET_MAX_CLIENTS; cnum++) { |
|
|
|
if (csock->clients[cnum] == NULL) break; |
|
|
|
if (csock.clients[cnum] == NULL) break; |
|
|
|
} |
|
|
|
} |
|
|
|
int sock = -1; |
|
|
|
int sock = -1; |
|
|
|
/* accept() new connection */ |
|
|
|
/* accept() new connection */ |
|
|
|
addrlen = sizeof(struct sockaddr_storage); |
|
|
|
addrlen = sizeof(struct sockaddr_storage); |
|
|
|
if ((sock = accept(csock->listen[i]->sock, (struct sockaddr *) &addr, &addrlen)) < 0) { |
|
|
|
if ((sock = accept(csock.listen[i]->sock, (struct sockaddr *) &addr, &addrlen)) < 0) { |
|
|
|
f2b_log_msg(log_error, "can't accept() new connection: %s", strerror(errno)); |
|
|
|
f2b_log_msg(log_error, "can't accept() new connection: %s", strerror(errno)); |
|
|
|
} else if (cnum < CSOCKET_MAX_CLIENTS) { |
|
|
|
} else if (cnum < CSOCKET_MAX_CLIENTS) { |
|
|
|
if ((conn = f2b_conn_create(RBUF_SIZE, WBUF_SIZE)) != NULL) { |
|
|
|
if ((conn = f2b_conn_create(RBUF_SIZE, WBUF_SIZE)) != NULL) { |
|
|
|
conn->flags = csock->listen[i]->flags; |
|
|
|
conn->flags = csock.listen[i]->flags; |
|
|
|
if (csock->listen[i]->flags & CSOCKET_CONN_TYPE_UNIX) { |
|
|
|
if (csock.listen[i]->flags & CSOCKET_CONN_TYPE_UNIX) { |
|
|
|
struct ucred peer; |
|
|
|
struct ucred peer; |
|
|
|
socklen_t peerlen = 0; |
|
|
|
socklen_t peerlen = 0; |
|
|
|
peerlen = sizeof(peer); |
|
|
|
peerlen = sizeof(peer); |
|
|
@ -480,9 +474,9 @@ f2b_csocket_poll(f2b_csock_t *csock, void (*cb)(const f2b_cmd_t *cmd, f2b_buf_t |
|
|
|
f2b_log_msg(log_debug, "new remote connection from %s, socket %d", conn->peer, sock); |
|
|
|
f2b_log_msg(log_debug, "new remote connection from %s, socket %d", conn->peer, sock); |
|
|
|
} |
|
|
|
} |
|
|
|
conn->sock = sock; |
|
|
|
conn->sock = sock; |
|
|
|
conn->password = csock->password; |
|
|
|
conn->password = csock.password; |
|
|
|
f2b_conn_update_challenge(conn); |
|
|
|
f2b_conn_update_challenge(conn); |
|
|
|
csock->clients[cnum] = conn; |
|
|
|
csock.clients[cnum] = conn; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
f2b_log_msg(log_error, "can't create new connection"); |
|
|
|
f2b_log_msg(log_error, "can't create new connection"); |
|
|
|
} |
|
|
|
} |
|
|
@ -493,14 +487,14 @@ f2b_csocket_poll(f2b_csock_t *csock, void (*cb)(const f2b_cmd_t *cmd, f2b_buf_t |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (int cnum = 0; cnum < CSOCKET_MAX_CLIENTS; cnum++) { |
|
|
|
for (int cnum = 0; cnum < CSOCKET_MAX_CLIENTS; cnum++) { |
|
|
|
if ((conn = csock->clients[cnum]) == NULL) |
|
|
|
if ((conn = csock.clients[cnum]) == NULL) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
retval = f2b_conn_process(conn, FD_ISSET(conn->sock, &rfds), cb); |
|
|
|
retval = f2b_conn_process(conn, FD_ISSET(conn->sock, &rfds), cb); |
|
|
|
if (retval < 0) { |
|
|
|
if (retval < 0) { |
|
|
|
f2b_log_msg(log_debug, "closing connection on socket %d", conn->sock); |
|
|
|
f2b_log_msg(log_debug, "closing connection on socket %d", conn->sock); |
|
|
|
shutdown(conn->sock, SHUT_RDWR); |
|
|
|
shutdown(conn->sock, SHUT_RDWR); |
|
|
|
f2b_conn_destroy(conn); |
|
|
|
f2b_conn_destroy(conn); |
|
|
|
csock->clients[cnum] = NULL; |
|
|
|
csock.clients[cnum] = NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
} /* foreach connection(s) */ |
|
|
|
} /* foreach connection(s) */ |
|
|
|
return; |
|
|
|
return; |
|
|
|