Module: kamailio Branch: master Commit: a902e4a032a85a7755de32eeadac800a1312e64f URL: https://github.com/kamailio/kamailio/commit/a902e4a032a85a7755de32eeadac800a...
Author: Daniel-Constantin Mierla miconda@gmail.com Committer: Daniel-Constantin Mierla miconda@gmail.com Date: 2023-10-13T17:33:51+02:00
core: tcp - limit number of accepted connections per src ip
- default 1024
---
Modified: src/core/tcp_conn.h Modified: src/core/tcp_main.c Modified: src/core/tcp_read.c
---
Diff: https://github.com/kamailio/kamailio/commit/a902e4a032a85a7755de32eeadac800a... Patch: https://github.com/kamailio/kamailio/commit/a902e4a032a85a7755de32eeadac800a...
---
diff --git a/src/core/tcp_conn.h b/src/core/tcp_conn.h index 4cb3da51f40..2a4a2dd7b0d 100644 --- a/src/core/tcp_conn.h +++ b/src/core/tcp_conn.h @@ -47,6 +47,8 @@
#define KSR_TCP_MSGREAD_TIMEOUT 20 /* timeout (secs) to read SIP message */
+#define KSR_TCP_ACCEPT_IPLIMIT 1024 /* limit accepted tcp connections from IP */ + /* tcp connection flags */ #define F_CONN_READ_W 2 /* watched for READ ev. in main */ #define F_CONN_WRITE_W 4 /* watched for WRITE (main) */ @@ -281,6 +283,7 @@ typedef struct tcp_connection unsigned int flags; /* connection related flags */ snd_flags_t send_flags; /* special send flags */ enum tcp_conn_states state; /* connection state */ + enum tcp_conn_states initstate; /* initial connection state */ void *extra_data; /* extra data associated to the connection, 0 for tcp*/ struct timer_ln timer; time_t timestamp; /* connection creation timestamp */ diff --git a/src/core/tcp_main.c b/src/core/tcp_main.c index 9f39dd72444..aac5347431d 100644 --- a/src/core/tcp_main.c +++ b/src/core/tcp_main.c @@ -1162,6 +1162,30 @@ int tcpconn_read_haproxy(struct tcp_connection *c) return (bytes >= 0) ? retval : -1; }
+int tcp_connection_limit_srcip(union sockaddr_union *srcaddr, int limit) +{ + struct tcp_connection *con; + ip_addr_t src_ip; + int n; + int i; + + n = 0; + su2ip_addr(&src_ip, srcaddr); + TCPCONN_LOCK; + for(i = 0; i < TCP_ID_HASH_SIZE && n < limit; i++) { + for(con = tcpconn_id_hash[i]; con && n < limit; con = con->id_next) { + if(con->initstate == S_CONN_ACCEPT) { + if(ip_addr_cmp(&src_ip, &con->rcv.src_ip)) { + n++; + } + } + } + } + TCPCONN_UNLOCK; + + return (n >= limit) ? 1 : 0; +} + struct tcp_connection *tcpconn_new(int sock, union sockaddr_union *su, union sockaddr_union *local_addr, struct socket_info *ba, int type, int state) @@ -1217,6 +1241,7 @@ struct tcp_connection *tcpconn_new(int sock, union sockaddr_union *su, c->rcv.proto_reserved1 = 0; /* this will be filled before receive_message*/ c->rcv.proto_reserved2 = 0; c->state = state; + c->initstate = state; c->extra_data = 0; c->timestamp = time(NULL); #ifdef USE_TLS @@ -4426,6 +4451,12 @@ static inline int handle_new_connect(struct socket_info *si) tcp_safe_close(new_sock); return 1; /* success, because the accept was successful */ } + if(unlikely(tcp_connection_limit_srcip(&su, KSR_TCP_ACCEPT_IPLIMIT))) { + LM_CRIT("hit the limit of connections per source IP (%s) - rejecting\n", + su2a(&su, sizeof(su))); + tcp_safe_close(new_sock); + return 1; /* success, because the accept was successful */ + } (*tcp_connections_no)++; if(unlikely(si->proto == PROTO_TLS)) (*tls_connections_no)++; diff --git a/src/core/tcp_read.c b/src/core/tcp_read.c index 2ad9579854f..31c6e92444c 100644 --- a/src/core/tcp_read.c +++ b/src/core/tcp_read.c @@ -448,7 +448,6 @@ int tcp_read_headers(struct tcp_connection *c, rd_conn_flags_t *read_flags) bytes = tcp_read(c, read_flags); if(bytes <= 0) return bytes; - LM_DBG("===== read %d bytes\n", bytes); gettimeofday(&tvnow, NULL); tvdiff = 1000000 * (tvnow.tv_sec - r->tvrstart.tv_sec) + (tvnow.tv_usec - r->tvrstart.tv_usec); @@ -1661,12 +1660,10 @@ int tcp_read_req(struct tcp_connection *con, int *bytes_read, req->content_len = 0; req->bytes_to_go = 0; req->pos = req->buf + size; - LM_DBG("=== reset message read start time\n"); req->tvrstart.tv_sec = 0; req->tvrstart.tv_usec = 0;
if(unlikely(size)) { - LM_DBG("=== set message read start time\n"); gettimeofday(&req->tvrstart, NULL); memmove(req->buf, req->parsed, size); req->parsed = req->buf; /* fix req->parsed after using it */