... | ... |
@@ -281,8 +281,8 @@ found: |
281 | 281 |
* be !=0 |
282 | 282 |
* port - used only if dst!=0 (else the port in send_info->to is used) |
283 | 283 |
* send_info - filled dest_info structure: |
284 |
- * if the send_socket memeber is null, a send_socket will be |
|
285 |
- * choosen automatically |
|
284 |
+ * if the send_socket member is null, a send_socket will be |
|
285 |
+ * chosen automatically |
|
286 | 286 |
* WARNING: don't forget to zero-fill all the unused members (a non-zero |
287 | 287 |
* random id along with proto==PROTO_TCP can have bad consequences, same for |
288 | 288 |
* a bogus send_socket value) |
... | ... |
@@ -112,7 +112,7 @@ static inline int msg_send(struct dest_info* dst, char* buf, int len) |
112 | 112 |
" support is disabled\n"); |
113 | 113 |
goto error; |
114 | 114 |
}else{ |
115 |
- if (tcp_send(dst, buf, len)<0){ |
|
115 |
+ if (tcp_send(dst, 0, buf, len)<0){ |
|
116 | 116 |
STATS_TX_DROPS; |
117 | 117 |
LOG(L_ERR, "msg_send: ERROR: tcp_send failed\n"); |
118 | 118 |
goto error; |
... | ... |
@@ -127,7 +127,7 @@ static inline int msg_send(struct dest_info* dst, char* buf, int len) |
127 | 127 |
" support is disabled\n"); |
128 | 128 |
goto error; |
129 | 129 |
}else{ |
130 |
- if (tcp_send(dst, buf, len)<0){ |
|
130 |
+ if (tcp_send(dst, 0, buf, len)<0){ |
|
131 | 131 |
STATS_TX_DROPS; |
132 | 132 |
LOG(L_ERR, "msg_send: ERROR: tcp_send failed\n"); |
133 | 133 |
goto error; |
... | ... |
@@ -32,6 +32,7 @@ |
32 | 32 |
* 2003-04-06 all ports are stored/passed in host byte order now (andrei) |
33 | 33 |
* 2006-04-20 comp support in recv_info and dest_info (andrei) |
34 | 34 |
* 2006-04-21 added init_dst_from_rcv (andrei) |
35 |
+ * 2007-06-26 added ip_addr_mk_any() (andrei) |
|
35 | 36 |
*/ |
36 | 37 |
|
37 | 38 |
#ifndef ip_addr_h |
... | ... |
@@ -43,6 +44,7 @@ |
43 | 44 |
#include <netinet/in.h> |
44 | 45 |
#include <netdb.h> |
45 | 46 |
#include "str.h" |
47 |
+#include "compiler_opt.h" |
|
46 | 48 |
|
47 | 49 |
|
48 | 50 |
#include "dprint.h" |
... | ... |
@@ -204,6 +206,31 @@ inline static int ip_addr_any(struct ip_addr* ip) |
204 | 206 |
|
205 | 207 |
|
206 | 208 |
|
209 |
+/* creates an ANY ip_addr (filled with 0, af and len properly set) */ |
|
210 |
+inline static void ip_addr_mk_any(int af, struct ip_addr* ip) |
|
211 |
+{ |
|
212 |
+ ip->af=af; |
|
213 |
+ if (likely(af==AF_INET)){ |
|
214 |
+ ip->len=4; |
|
215 |
+ ip->u.addr32[0]=0; |
|
216 |
+ } |
|
217 |
+#ifdef USE_IPV6 |
|
218 |
+ else{ |
|
219 |
+ ip->len=16; |
|
220 |
+#if (defined (ULONG_MAX) && ULONG_MAX > 4294967295) || defined LP64 |
|
221 |
+ /* long is 64 bits */ |
|
222 |
+ ip->u.addrl[0]=0; |
|
223 |
+ ip->u.addrl[1]=0; |
|
224 |
+#else |
|
225 |
+ ip->u.addr32[0]=0; |
|
226 |
+ ip->u.addr32[1]=0; |
|
227 |
+ ip->u.addr32[2]=0; |
|
228 |
+ ip->u.addr32[3]=0; |
|
229 |
+#endif /* ULONG_MAX */ |
|
230 |
+ } |
|
231 |
+#endif |
|
232 |
+} |
|
233 |
+ |
|
207 | 234 |
/* returns 1 if ip & net.mask == net.ip ; 0 otherwise & -1 on error |
208 | 235 |
[ diff. address families ]) */ |
209 | 236 |
inline static int matchnet(struct ip_addr* ip, struct net* net) |
... | ... |
@@ -196,7 +196,7 @@ static int check_via_address(struct ip_addr* ip, str *name, |
196 | 196 |
if (resolver&DO_DNS){ |
197 | 197 |
DBG("check_via_address: doing dns lookup\n"); |
198 | 198 |
/* try all names ips */ |
199 |
- he=sip_resolvehost(name, &port, 0); /* FIXME proto? */ |
|
199 |
+ he=sip_resolvehost(name, &port, 0); /* don't use naptr */ |
|
200 | 200 |
if (he && ip->af==he->h_addrtype){ |
201 | 201 |
for(i=0;he && he->h_addr_list[i];i++){ |
202 | 202 |
if ( memcmp(&he->h_addr_list[i], ip->u.addr, ip->len)==0) |
... | ... |
@@ -31,6 +31,8 @@ |
31 | 31 |
* 2003-06-30 added tcp_connection flags & state (andrei) |
32 | 32 |
* 2003-10-27 tcp port aliases support added (andrei) |
33 | 33 |
* 2006-10-13 added tcp_req_states for STUN (vlada) |
34 |
+ * 2007-07-26 improved tcp connection hash function; increased aliases |
|
35 |
+ * hash size (andrei) |
|
34 | 36 |
*/ |
35 | 37 |
|
36 | 38 |
|
... | ... |
@@ -43,7 +45,8 @@ |
43 | 45 |
#include "atomic_ops.h" |
44 | 46 |
#include "timer_ticks.h" |
45 | 47 |
|
46 |
-#define TCP_CON_MAX_ALIASES 4 /* maximum number of port aliases */ |
|
48 |
+/* maximum number of port aliases x search wildcard possibilities */ |
|
49 |
+#define TCP_CON_MAX_ALIASES (4*3) |
|
47 | 50 |
|
48 | 51 |
#define TCP_BUF_SIZE 4096 |
49 | 52 |
#define DEFAULT_TCP_CONNECTION_LIFETIME 120 /* in seconds */ |
... | ... |
@@ -180,25 +183,41 @@ struct tcp_connection{ |
180 | 183 |
#define TCPCONN_LOCK lock_get(tcpconn_lock); |
181 | 184 |
#define TCPCONN_UNLOCK lock_release(tcpconn_lock); |
182 | 185 |
|
183 |
-#define TCP_ALIAS_HASH_SIZE 1024 |
|
186 |
+#define TCP_ALIAS_HASH_SIZE 4096 |
|
184 | 187 |
#define TCP_ID_HASH_SIZE 1024 |
185 | 188 |
|
186 |
-static inline unsigned tcp_addr_hash(struct ip_addr* ip, unsigned short port) |
|
189 |
+/* hash (dst_ip, dst_port, local_ip, local_port) */ |
|
190 |
+static inline unsigned tcp_addr_hash( struct ip_addr* ip, |
|
191 |
+ unsigned short port, |
|
192 |
+ struct ip_addr* l_ip, |
|
193 |
+ unsigned short l_port) |
|
187 | 194 |
{ |
188 |
- if(ip->len==4) return (ip->u.addr32[0]^port)&(TCP_ALIAS_HASH_SIZE-1); |
|
195 |
+ unsigned h; |
|
196 |
+ |
|
197 |
+ if(ip->len==4) |
|
198 |
+ h=(ip->u.addr32[0]^port)^(l_ip->u.addr32[0]^l_port); |
|
189 | 199 |
else if (ip->len==16) |
190 |
- return (ip->u.addr32[0]^ip->u.addr32[1]^ip->u.addr32[2]^ |
|
191 |
- ip->u.addr32[3]^port) & (TCP_ALIAS_HASH_SIZE-1); |
|
200 |
+ h= (ip->u.addr32[0]^ip->u.addr32[1]^ip->u.addr32[2]^ |
|
201 |
+ ip->u.addr32[3]^port) ^ |
|
202 |
+ (l_ip->u.addr32[0]^l_ip->u.addr32[1]^l_ip->u.addr32[2]^ |
|
203 |
+ l_ip->u.addr32[3]^l_port); |
|
192 | 204 |
else{ |
193 | 205 |
LOG(L_CRIT, "tcp_addr_hash: BUG: bad len %d for an ip address\n", |
194 | 206 |
ip->len); |
195 | 207 |
return 0; |
196 | 208 |
} |
209 |
+ /* make sure the first bits are influenced by all 32 |
|
210 |
+ * (the first log2(TCP_ALIAS_HASH_SIZE) bits should be a mix of all |
|
211 |
+ * 32)*/ |
|
212 |
+ h ^= h>>17; |
|
213 |
+ h ^= h>>7; |
|
214 |
+ return h & (TCP_ALIAS_HASH_SIZE-1); |
|
197 | 215 |
} |
198 | 216 |
|
199 | 217 |
#define tcp_id_hash(id) (id&(TCP_ID_HASH_SIZE-1)) |
200 | 218 |
|
201 | 219 |
struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port, |
220 |
+ union sockaddr_union* local_addr, |
|
202 | 221 |
ticks_t timeout); |
203 | 222 |
|
204 | 223 |
#endif |
... | ... |
@@ -75,6 +75,8 @@ |
75 | 75 |
* result in inf. lifetime) (andrei) |
76 | 76 |
* 2007-07-25 tcpconn_connect can now bind the socket on a specified |
77 | 77 |
* source addr/port (andrei) |
78 |
+ * 2007-07-26 tcp_send() and tcpconn_get() can now use a specified source |
|
79 |
+ * addr./port (andrei) |
|
78 | 80 |
*/ |
79 | 81 |
|
80 | 82 |
|
... | ... |
@@ -202,6 +204,11 @@ static io_wait_h io_h; |
202 | 204 |
|
203 | 205 |
|
204 | 206 |
|
207 |
+inline static int _tcpconn_add_alias_unsafe(struct tcp_connection* c, int port, |
|
208 |
+ struct ip_addr* l_ip, int l_port); |
|
209 |
+ |
|
210 |
+ |
|
211 |
+ |
|
205 | 212 |
/* sets source address used when opening new sockets and no source is specified |
206 | 213 |
* (by default the address is choosen by the kernel) |
207 | 214 |
* Should be used only on init. |
... | ... |
@@ -589,23 +596,36 @@ error: |
589 | 596 |
|
590 | 597 |
/* adds a tcp connection to the tcpconn hashes |
591 | 598 |
* Note: it's called _only_ from the tcp_main process */ |
592 |
-struct tcp_connection* tcpconn_add(struct tcp_connection *c) |
|
599 |
+inline static struct tcp_connection* tcpconn_add(struct tcp_connection *c) |
|
593 | 600 |
{ |
601 |
+ struct ip_addr zero_ip; |
|
594 | 602 |
|
595 |
- if (c){ |
|
603 |
+ if (likely(c)){ |
|
604 |
+ ip_addr_mk_any(c->rcv.src_ip.af, &zero_ip); |
|
596 | 605 |
c->id_hash=tcp_id_hash(c->id); |
597 |
- c->con_aliases[0].hash=tcp_addr_hash(&c->rcv.src_ip, c->rcv.src_port); |
|
606 |
+ c->aliases=0; |
|
598 | 607 |
TCPCONN_LOCK; |
599 | 608 |
/* add it at the begining of the list*/ |
600 | 609 |
tcpconn_listadd(tcpconn_id_hash[c->id_hash], c, id_next, id_prev); |
601 |
- /* set the first alias */ |
|
602 |
- c->con_aliases[0].port=c->rcv.src_port; |
|
603 |
- c->con_aliases[0].parent=c; |
|
604 |
- tcpconn_listadd(tcpconn_aliases_hash[c->con_aliases[0].hash], |
|
605 |
- &c->con_aliases[0], next, prev); |
|
606 |
- c->aliases++; |
|
610 |
+ /* set the aliases */ |
|
611 |
+ /* first alias is for (peer_ip, peer_port, 0 ,0) -- for finding |
|
612 |
+ * any connection to peer_ip, peer_port |
|
613 |
+ * the second alias is for (peer_ip, peer_port, local_addr, 0) -- for |
|
614 |
+ * finding any conenction to peer_ip, peer_port from local_addr |
|
615 |
+ * the third alias is for (peer_ip, peer_port, local_addr, local_port) |
|
616 |
+ * -- for finding if a fully specified connection exists */ |
|
617 |
+ _tcpconn_add_alias_unsafe(c, c->rcv.src_port, &zero_ip, 0); |
|
618 |
+ _tcpconn_add_alias_unsafe(c, c->rcv.src_port, &c->rcv.dst_ip, 0); |
|
619 |
+ _tcpconn_add_alias_unsafe(c, c->rcv.src_port, &c->rcv.dst_ip, |
|
620 |
+ c->rcv.dst_port); |
|
621 |
+ /* ignore add_alias errors, there are some valid cases when one |
|
622 |
+ * of the add_alias would fail (e.g. first add_alias for 2 connections |
|
623 |
+ * with the same destination but different src. ip*/ |
|
607 | 624 |
TCPCONN_UNLOCK; |
608 |
- DBG("tcpconn_add: hashes: %d, %d\n", c->con_aliases[0].hash, |
|
625 |
+ DBG("tcpconn_add: hashes: %d:%d:%d, %d\n", |
|
626 |
+ c->con_aliases[0].hash, |
|
627 |
+ c->con_aliases[1].hash, |
|
628 |
+ c->con_aliases[2].hash, |
|
609 | 629 |
c->id_hash); |
610 | 630 |
return c; |
611 | 631 |
}else{ |
... | ... |
@@ -651,15 +671,20 @@ void tcpconn_rm(struct tcp_connection* c) |
651 | 671 |
} |
652 | 672 |
|
653 | 673 |
|
654 |
-/* finds a connection, if id=0 uses the ip addr & port (host byte order) |
|
674 |
+/* finds a connection, if id=0 uses the ip addr, port, local_ip and local port |
|
675 |
+ * (host byte order) and tries to find the connection that matches all of |
|
676 |
+ * them. Wild cards can be used for local_ip and local_port (a 0 filled |
|
677 |
+ * ip address and/or a 0 local port). |
|
655 | 678 |
* WARNING: unprotected (locks) use tcpconn_get unless you really |
656 | 679 |
* know what you are doing */ |
657 |
-struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port) |
|
680 |
+struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port, |
|
681 |
+ struct ip_addr* l_ip, int l_port) |
|
658 | 682 |
{ |
659 | 683 |
|
660 | 684 |
struct tcp_connection *c; |
661 | 685 |
struct tcp_conn_alias* a; |
662 | 686 |
unsigned hash; |
687 |
+ int is_local_ip_any; |
|
663 | 688 |
|
664 | 689 |
#ifdef EXTRA_DEBUG |
665 | 690 |
DBG("tcpconn_find: %d port %d\n",id, port); |
... | ... |
@@ -675,7 +700,8 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port) |
675 | 700 |
if ((id==c->id)&&(c->state!=S_CONN_BAD)) return c; |
676 | 701 |
} |
677 | 702 |
}else if (ip){ |
678 |
- hash=tcp_addr_hash(ip, port); |
|
703 |
+ hash=tcp_addr_hash(ip, port, l_ip, l_port); |
|
704 |
+ is_local_ip_any=ip_addr_any(l_ip); |
|
679 | 705 |
for (a=tcpconn_aliases_hash[hash]; a; a=a->next){ |
680 | 706 |
#ifdef EXTRA_DEBUG |
681 | 707 |
DBG("a=%p, c=%p, c->id=%d, alias port= %d port=%d\n", a, a->parent, |
... | ... |
@@ -683,7 +709,11 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port) |
683 | 709 |
print_ip("ip=",&a->parent->rcv.src_ip,"\n"); |
684 | 710 |
#endif |
685 | 711 |
if ( (a->parent->state!=S_CONN_BAD) && (port==a->port) && |
686 |
- (ip_addr_cmp(ip, &a->parent->rcv.src_ip)) ) |
|
712 |
+ ((l_port==0) || (l_port==a->parent->rcv.dst_port)) && |
|
713 |
+ (ip_addr_cmp(ip, &a->parent->rcv.src_ip)) && |
|
714 |
+ (is_local_ip_any || |
|
715 |
+ ip_addr_cmp(l_ip, &a->parent->rcv.dst_ip)) |
|
716 |
+ ) |
|
687 | 717 |
return a->parent; |
688 | 718 |
} |
689 | 719 |
} |
... | ... |
@@ -692,13 +722,30 @@ struct tcp_connection* _tcpconn_find(int id, struct ip_addr* ip, int port) |
692 | 722 |
|
693 | 723 |
|
694 | 724 |
|
695 |
-/* _tcpconn_find with locks and timeout */ |
|
725 |
+/* _tcpconn_find with locks and timeout |
|
726 |
+ * local_addr contains the desired local ip:port. If null any local address |
|
727 |
+ * will be used. IN*ADDR_ANY or 0 port are wild cards. |
|
728 |
+ */ |
|
696 | 729 |
struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port, |
730 |
+ union sockaddr_union* local_addr, |
|
697 | 731 |
ticks_t timeout) |
698 | 732 |
{ |
699 | 733 |
struct tcp_connection* c; |
734 |
+ struct ip_addr local_ip; |
|
735 |
+ int local_port; |
|
736 |
+ |
|
737 |
+ local_port=0; |
|
738 |
+ if (ip){ |
|
739 |
+ if (local_addr){ |
|
740 |
+ su2ip_addr(&local_ip, local_addr); |
|
741 |
+ local_port=su_getport(local_addr); |
|
742 |
+ }else{ |
|
743 |
+ ip_addr_mk_any(ip->af, &local_ip); |
|
744 |
+ local_port=0; |
|
745 |
+ } |
|
746 |
+ } |
|
700 | 747 |
TCPCONN_LOCK; |
701 |
- c=_tcpconn_find(id, ip, port); |
|
748 |
+ c=_tcpconn_find(id, ip, port, &local_ip, local_port); |
|
702 | 749 |
if (c){ |
703 | 750 |
atomic_inc(&c->refcnt); |
704 | 751 |
c->timeout=get_ticks_raw()+timeout; |
... | ... |
@@ -709,26 +756,29 @@ struct tcp_connection* tcpconn_get(int id, struct ip_addr* ip, int port, |
709 | 756 |
|
710 | 757 |
|
711 | 758 |
|
712 |
-/* add port as an alias for the "id" connection |
|
713 |
- * returns 0 on success,-1 on failure */ |
|
714 |
-int tcpconn_add_alias(int id, int port, int proto) |
|
759 |
+/* add c->dst:port, local_addr as an alias for the "id" connection, |
|
760 |
+ * returns 0 on success, <0 on failure ( -1 - null c, -2 too many aliases, |
|
761 |
+ * -3 alias already present and pointing to another connection) |
|
762 |
+ * WARNING: must be called with TCPCONN_LOCK held */ |
|
763 |
+inline static int _tcpconn_add_alias_unsafe(struct tcp_connection* c, int port, |
|
764 |
+ struct ip_addr* l_ip, int l_port) |
|
715 | 765 |
{ |
716 |
- struct tcp_connection* c; |
|
717 | 766 |
unsigned hash; |
718 | 767 |
struct tcp_conn_alias* a; |
768 |
+ int is_local_ip_any; |
|
719 | 769 |
|
720 | 770 |
a=0; |
721 |
- /* fix the port */ |
|
722 |
- port=port?port:((proto==PROTO_TLS)?SIPS_PORT:SIP_PORT); |
|
723 |
- TCPCONN_LOCK; |
|
724 |
- /* check if alias already exists */ |
|
725 |
- c=_tcpconn_find(id, 0, 0); |
|
771 |
+ is_local_ip_any=ip_addr_any(l_ip); |
|
726 | 772 |
if (c){ |
727 |
- hash=tcp_addr_hash(&c->rcv.src_ip, port); |
|
773 |
+ hash=tcp_addr_hash(&c->rcv.src_ip, port, l_ip, l_port); |
|
728 | 774 |
/* search the aliases for an already existing one */ |
729 | 775 |
for (a=tcpconn_aliases_hash[hash]; a; a=a->next){ |
730 | 776 |
if ( (a->parent->state!=S_CONN_BAD) && (port==a->port) && |
731 |
- (ip_addr_cmp(&c->rcv.src_ip, &a->parent->rcv.src_ip)) ){ |
|
777 |
+ ( (l_port==0) || (l_port==a->parent->rcv.dst_port)) && |
|
778 |
+ (ip_addr_cmp(&c->rcv.src_ip, &a->parent->rcv.src_ip)) && |
|
779 |
+ ( is_local_ip_any || |
|
780 |
+ ip_addr_cmp(&a->parent->rcv.dst_ip, l_ip)) |
|
781 |
+ ){ |
|
732 | 782 |
/* found */ |
733 | 783 |
if (a->parent!=c) goto error_sec; |
734 | 784 |
else goto ok; |
... | ... |
@@ -743,38 +793,88 @@ int tcpconn_add_alias(int id, int port, int proto) |
743 | 793 |
c->aliases++; |
744 | 794 |
}else goto error_not_found; |
745 | 795 |
ok: |
746 |
- TCPCONN_UNLOCK; |
|
747 | 796 |
#ifdef EXTRA_DEBUG |
748 |
- if (a) DBG("tcpconn_add_alias: alias already present\n"); |
|
749 |
- else DBG("tcpconn_add_alias: alias port %d for hash %d, id %d\n", |
|
797 |
+ if (a) DBG("_tcpconn_add_alias_unsafe: alias already present\n"); |
|
798 |
+ else DBG("_tcpconn_add_alias_unsafe: alias port %d for hash %d, id %d\n", |
|
750 | 799 |
port, hash, c->id); |
751 | 800 |
#endif |
752 | 801 |
return 0; |
753 | 802 |
error_aliases: |
754 |
- TCPCONN_UNLOCK; |
|
755 |
- LOG(L_ERR, "ERROR: tcpconn_add_alias: too many aliases for connection %p" |
|
756 |
- " (%d)\n", c, c->id); |
|
803 |
+ /* too many aliases */ |
|
804 |
+ return -2; |
|
805 |
+error_not_found: |
|
806 |
+ /* null connection */ |
|
757 | 807 |
return -1; |
808 |
+error_sec: |
|
809 |
+ /* alias already present and pointing to a different connection |
|
810 |
+ * (hijack attempt?) */ |
|
811 |
+ return -3; |
|
812 |
+} |
|
813 |
+ |
|
814 |
+ |
|
815 |
+ |
|
816 |
+/* add port as an alias for the "id" connection, |
|
817 |
+ * returns 0 on success,-1 on failure */ |
|
818 |
+int tcpconn_add_alias(int id, int port, int proto) |
|
819 |
+{ |
|
820 |
+ struct tcp_connection* c; |
|
821 |
+ int ret; |
|
822 |
+ struct ip_addr zero_ip; |
|
823 |
+ |
|
824 |
+ /* fix the port */ |
|
825 |
+ port=port?port:((proto==PROTO_TLS)?SIPS_PORT:SIP_PORT); |
|
826 |
+ TCPCONN_LOCK; |
|
827 |
+ /* check if alias already exists */ |
|
828 |
+ c=_tcpconn_find(id, 0, 0, 0, 0); |
|
829 |
+ if (c){ |
|
830 |
+ ip_addr_mk_any(c->rcv.src_ip.af, &zero_ip); |
|
831 |
+ |
|
832 |
+ /* alias src_ip:port, 0, 0 */ |
|
833 |
+ ret=_tcpconn_add_alias_unsafe(c, port, &zero_ip, 0); |
|
834 |
+ if (ret<0 && ret!=-3) goto error; |
|
835 |
+ /* alias src_ip:port, local_ip, 0 */ |
|
836 |
+ ret=_tcpconn_add_alias_unsafe(c, port, &c->rcv.dst_ip, 0); |
|
837 |
+ if (ret<0 && ret!=-3) goto error; |
|
838 |
+ /* alias src_ip:port, local_ip, local_port */ |
|
839 |
+ ret=_tcpconn_add_alias_unsafe(c, port, &c->rcv.dst_ip, |
|
840 |
+ c->rcv.dst_port); |
|
841 |
+ if (ret<0) goto error; |
|
842 |
+ }else goto error_not_found; |
|
843 |
+ TCPCONN_UNLOCK; |
|
844 |
+ return 0; |
|
758 | 845 |
error_not_found: |
759 | 846 |
TCPCONN_UNLOCK; |
760 | 847 |
LOG(L_ERR, "ERROR: tcpconn_add_alias: no connection found for id %d\n",id); |
761 | 848 |
return -1; |
762 |
-error_sec: |
|
849 |
+error: |
|
763 | 850 |
TCPCONN_UNLOCK; |
764 |
- LOG(L_ERR, "ERROR: tcpconn_add_alias: possible port hijack attempt\n"); |
|
765 |
- LOG(L_ERR, "ERROR: tcpconn_add_alias: alias already present and points" |
|
766 |
- " to another connection (%d : %d and %d : %d)\n", |
|
767 |
- a->parent->id, port, c->id, port); |
|
851 |
+ switch(ret){ |
|
852 |
+ case -2: |
|
853 |
+ LOG(L_ERR, "ERROR: tcpconn_add_alias: too many aliases" |
|
854 |
+ " for connection %p (%d)\n", c, c->id); |
|
855 |
+ break; |
|
856 |
+ case -3: |
|
857 |
+ LOG(L_ERR, "ERROR: tcpconn_add_alias: possible port" |
|
858 |
+ " hijack attempt\n"); |
|
859 |
+ LOG(L_ERR, "ERROR: tcpconn_add_alias: alias for %d port %d already" |
|
860 |
+ " present and points to another connection \n", |
|
861 |
+ c->id, port); |
|
862 |
+ break; |
|
863 |
+ default: |
|
864 |
+ LOG(L_ERR, "ERROR: tcpconn_add_alias: unkown error %d\n", ret); |
|
865 |
+ } |
|
768 | 866 |
return -1; |
769 | 867 |
} |
770 | 868 |
|
771 | 869 |
|
772 | 870 |
|
773 | 871 |
/* finds a tcpconn & sends on it |
774 |
- * uses the dst members to, proto (TCP|TLS) and id |
|
872 |
+ * uses the dst members to, proto (TCP|TLS) and id and tries to send |
|
873 |
+ * from the "from" address (if non null and id==0) |
|
775 | 874 |
* returns: number of bytes written (>=0) on success |
776 | 875 |
* <0 on error */ |
777 |
-int tcp_send(struct dest_info* dst, char* buf, unsigned len) |
|
876 |
+int tcp_send(struct dest_info* dst, union sockaddr_union* from, |
|
877 |
+ char* buf, unsigned len) |
|
778 | 878 |
{ |
779 | 879 |
struct tcp_connection *c; |
780 | 880 |
struct tcp_connection *tmp; |
... | ... |
@@ -783,14 +883,13 @@ int tcp_send(struct dest_info* dst, char* buf, unsigned len) |
783 | 883 |
int fd; |
784 | 884 |
long response[2]; |
785 | 885 |
int n; |
786 |
- union sockaddr_union* from; |
|
787 | 886 |
|
788 | 887 |
port=su_getport(&dst->to); |
789 | 888 |
if (port){ |
790 | 889 |
su2ip_addr(&ip, &dst->to); |
791 |
- c=tcpconn_get(dst->id, &ip, port, tcp_con_lifetime); |
|
890 |
+ c=tcpconn_get(dst->id, &ip, port, from, tcp_con_lifetime); |
|
792 | 891 |
}else if (dst->id){ |
793 |
- c=tcpconn_get(dst->id, 0, 0, tcp_con_lifetime); |
|
892 |
+ c=tcpconn_get(dst->id, 0, 0, 0, tcp_con_lifetime); |
|
794 | 893 |
}else{ |
795 | 894 |
LOG(L_CRIT, "BUG: tcp_send called with null id & to\n"); |
796 | 895 |
return -1; |
... | ... |
@@ -800,7 +899,7 @@ int tcp_send(struct dest_info* dst, char* buf, unsigned len) |
800 | 899 |
if (c==0) { |
801 | 900 |
if (port){ |
802 | 901 |
/* try again w/o id */ |
803 |
- c=tcpconn_get(0, &ip, port, tcp_con_lifetime); |
|
902 |
+ c=tcpconn_get(0, &ip, port, from, tcp_con_lifetime); |
|
804 | 903 |
goto no_id; |
805 | 904 |
}else{ |
806 | 905 |
LOG(L_ERR, "ERROR: tcp_send: id %d not found, dropping\n", |
... | ... |
@@ -813,7 +912,7 @@ no_id: |
813 | 912 |
if (c==0){ |
814 | 913 |
DBG("tcp_send: no open tcp connection found, opening new one\n"); |
815 | 914 |
/* create tcp connection */ |
816 |
- from=0; |
|
915 |
+ if (from==0){ |
|
817 | 916 |
/* check to see if we have to use a specific source addr. */ |
818 | 917 |
switch (dst->to.s.sa_family) { |
819 | 918 |
case AF_INET: |
... | ... |
@@ -828,6 +927,7 @@ no_id: |
828 | 927 |
/* error, bad af, ignore ... */ |
829 | 928 |
break; |
830 | 929 |
} |
930 |
+ } |
|
831 | 931 |
if ((c=tcpconn_connect(&dst->to, from, dst->proto))==0){ |
832 | 932 |
LOG(L_ERR, "ERROR: tcp_send: connect failed\n"); |
833 | 933 |
return -1; |
... | ... |
@@ -34,7 +34,8 @@ |
34 | 34 |
|
35 | 35 |
/* "public" functions*/ |
36 | 36 |
|
37 |
-int tcp_send(struct dest_info* dst, char* buf, unsigned len); |
|
37 |
+int tcp_send(struct dest_info* dst, union sockaddr_union* from, |
|
38 |
+ char* buf, unsigned len); |
|
38 | 39 |
|
39 | 40 |
int tcpconn_add_alias(int id, int port, int proto); |
40 | 41 |
|