Browse code

sctp multi-homing config support

- config support for sctp multi-homing (listen on multiple addresses in the
same time).
Format: sctp:(addr1, addr2, addr3)
sctp:(eth0) -> will listen on all eth0 addresses in the same
time
(eth0,lo) -> sctp will listen on all addresses from eth0 & lo
in the same time, while the other protocols will
create different socket for each of the addresses
(e.g.: for udp it would be equivalent with:
listen= udp:eth0 udp:lo)
The first address is always the main one.
Conflicts are resolved automatically, by removing the duplicates. Main
addresses have priority (e.g: sctp:(lo,eth0) sctp:(eth0,eth1) after
duplicate removal will become sctp:(lo) sctp:(eth0,eth1)).

- try to always keep the order in which listen addresses were given in
config (fixes reordering between interface names and hostnames, e.g.
listen= eth0 foo.bar resulted in ip(foo.bar) , ip(eth0) )

Andrei Pelinescu-Onciul authored on 18/08/2008 14:55:13
Showing 7 changed files
... ...
@@ -175,6 +175,7 @@ static void yyerror(char* s);
175 175
 static char* tmp;
176 176
 static int i_tmp;
177 177
 static struct socket_id* lst_tmp;
178
+static struct name_lst*  nl_tmp;
178 179
 static int rt;  /* Type of route block for find_export */
179 180
 static str* str_tmp;
180 181
 static str s_tmp;
... ...
@@ -186,6 +187,10 @@ static struct action *mod_func_action;
186 187
 
187 188
 static void warn(char* s);
188 189
 static struct socket_id* mk_listen_id(char*, int, int);
190
+static struct name_lst* mk_name_lst(char* name, int flags);
191
+static struct socket_id* mk_listen_id2(struct name_lst*, int, int);
192
+static void free_name_lst(struct name_lst* lst);
193
+static void free_socket_id_lst(struct socket_id* i);
189 194
 
190 195
 %}
191 196
 
... ...
@@ -198,6 +203,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
198 203
 	struct net* ipnet;
199 204
 	struct ip_addr* ipaddr;
200 205
 	struct socket_id* sockid;
206
+	struct name_lst* name_l;
201 207
 	struct avp_spec* attr;
202 208
 	select_t* select;
203 209
 }
... ...
@@ -466,8 +472,11 @@ static struct socket_id* mk_listen_id(char*, int, int);
466 472
 %type <ipnet> ipnet
467 473
 %type <strval> host
468 474
 %type <strval> listen_id
475
+%type <name_l> listen_id_lst
476
+%type <name_l> listen_id2
469 477
 %type <sockid>  id_lst
470 478
 %type <sockid>  phostport
479
+%type <sockid>  listen_phostport
471 480
 %type <intval> proto port
472 481
 %type <intval> equalop strop intop binop
473 482
 %type <strval> host_sep
... ...
@@ -550,6 +559,20 @@ listen_id:
550 559
 		}
551 560
 	}
552 561
 	;
562
+
563
+
564
+listen_id_lst:
565
+	listen_id	{ $$=mk_name_lst($1, SI_IS_MHOMED); }
566
+	| listen_id COMMA listen_id_lst	{ $$=mk_name_lst($1, SI_IS_MHOMED); 
567
+										if ($$) $$->next=$3;
568
+									}
569
+	;
570
+
571
+listen_id2:
572
+	LPAREN listen_id_lst RPAREN { $$=$2; }
573
+	| listen_id	{ $$=mk_name_lst($1, 0); }
574
+	;
575
+
553 576
 proto:
554 577
 	UDP	{ $$=PROTO_UDP; }
555 578
 	| TCP	{ $$=PROTO_TCP; }
... ...
@@ -568,9 +591,18 @@ phostport:
568 591
 	| proto COLON listen_id COLON port	{ $$=mk_listen_id($3, $1, $5);}
569 592
 	| listen_id COLON error { $$=0; yyerror(" port number expected"); }
570 593
 	;
594
+
595
+listen_phostport:
596
+	listen_id2		{ $$=mk_listen_id2($1, 0, 0); }
597
+	| listen_id2 COLON port	{ $$=mk_listen_id2($1, 0, $3); }
598
+	| proto COLON listen_id2	{ $$=mk_listen_id2($3, $1, 0); }
599
+	| proto COLON listen_id2 COLON port	{ $$=mk_listen_id2($3, $1, $5);}
600
+	| listen_id2 COLON error { $$=0; yyerror(" port number expected"); }
601
+	;
602
+
571 603
 id_lst:
572
-	phostport		{  $$=$1 ; }
573
-	| phostport id_lst	{ $$=$1; $$->next=$2; }
604
+	listen_phostport		{  $$=$1 ; }
605
+	| listen_phostport id_lst	{ $$=$1; $$->next=$2; }
574 606
 	;
575 607
 
576 608
 flags_decl:		FLAGS_DECL	flag_list
... ...
@@ -1107,16 +1139,28 @@ assign_stm:
1107 1139
 	| REPLY_TO_VIA EQUAL error { yyerror("boolean value expected"); }
1108 1140
 	| LISTEN EQUAL id_lst {
1109 1141
 		for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next) {
1110
-			if (add_listen_iface(lst_tmp->name, lst_tmp->port, lst_tmp->proto, 0)!=0) {
1111
-				LOG(L_CRIT,  "ERROR: cfg. parser: failed to add listen address\n");
1142
+			if (add_listen_iface(	lst_tmp->addr_lst->name,
1143
+									lst_tmp->addr_lst->next,
1144
+									lst_tmp->port, lst_tmp->proto,
1145
+									lst_tmp->flags)!=0) {
1146
+				LOG(L_CRIT,  "ERROR: cfg. parser: failed to add listen"
1147
+								" address\n");
1112 1148
 				break;
1113 1149
 			}
1114 1150
 		}
1151
+		free_socket_id_lst($3);
1115 1152
 	}
1116 1153
 	| LISTEN EQUAL  error { yyerror("ip address or hostname expected"); }
1117 1154
 	| ALIAS EQUAL  id_lst {
1118
-		for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next)
1119
-			add_alias(lst_tmp->name, strlen(lst_tmp->name), lst_tmp->port, lst_tmp->proto);
1155
+		for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next){
1156
+			add_alias(	lst_tmp->addr_lst->name,
1157
+						strlen(lst_tmp->addr_lst->name),
1158
+						lst_tmp->port, lst_tmp->proto);
1159
+			for (nl_tmp=lst_tmp->addr_lst->next; nl_tmp; nl_tmp=nl_tmp->next)
1160
+				add_alias(nl_tmp->name, strlen(nl_tmp->name),
1161
+							lst_tmp->port, lst_tmp->proto);
1162
+		}
1163
+		free_socket_id_lst($3);
1120 1164
 	}
1121 1165
 	| ALIAS  EQUAL error  { yyerror(" hostname expected"); }
1122 1166
 	| ADVERTISED_ADDRESS EQUAL listen_id {
... ...
@@ -2289,8 +2333,12 @@ cmd:
2289 2333
 	}
2290 2334
 	| SET_ADV_PORT LPAREN error RPAREN { $$=0; yyerror("bad argument, string expected"); }
2291 2335
 	| SET_ADV_PORT  error {$$=0; yyerror("missing '(' or ')' ?"); }
2292
-	| FORCE_SEND_SOCKET LPAREN phostport RPAREN { $$=mk_action(FORCE_SEND_SOCKET_T, 1, SOCKID_ST, $3); }
2293
-	| FORCE_SEND_SOCKET LPAREN error RPAREN { $$=0; yyerror("bad argument, [proto:]host[:port] expected"); }
2336
+	| FORCE_SEND_SOCKET LPAREN phostport RPAREN { 
2337
+		$$=mk_action(FORCE_SEND_SOCKET_T, 1, SOCKID_ST, $3);
2338
+	}
2339
+	| FORCE_SEND_SOCKET LPAREN error RPAREN {
2340
+		$$=0; yyerror("bad argument, [proto:]host[:port] expected");
2341
+	}
2294 2342
 	| FORCE_SEND_SOCKET error {$$=0; yyerror("missing '(' or ')' ?"); }
2295 2343
 	| ID {mod_func_action = mk_action(MODULE_T, 2, MODEXP_ST, NULL, NUMBER_ST, 0); } LPAREN func_params RPAREN	{
2296 2344
 		mod_func_action->val[0].u.data = find_export_record($1, mod_func_action->val[1].u.number, rt);
... ...
@@ -2352,6 +2400,21 @@ static void yyerror(char* s)
2352 2400
 }
2353 2401
 
2354 2402
 
2403
+static struct name_lst* mk_name_lst(char* host, int flags)
2404
+{
2405
+	struct name_lst* l;
2406
+	l=pkg_malloc(sizeof(struct name_lst));
2407
+	if (l==0) {
2408
+		LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n");
2409
+	} else {
2410
+		l->name=host;
2411
+		l->flags=flags;
2412
+		l->next=0;
2413
+	}
2414
+	return l;
2415
+}
2416
+
2417
+
2355 2418
 static struct socket_id* mk_listen_id(char* host, int proto, int port)
2356 2419
 {
2357 2420
 	struct socket_id* l;
... ...
@@ -2359,7 +2422,12 @@ static struct socket_id* mk_listen_id(char* host, int proto, int port)
2359 2422
 	if (l==0) {
2360 2423
 		LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n");
2361 2424
 	} else {
2362
-		l->name=host;
2425
+		l->addr_lst=mk_name_lst(host, 0);
2426
+		if (l->addr_lst==0){
2427
+			pkg_free(l);
2428
+			return 0;
2429
+		}
2430
+		l->flags=0;
2363 2431
 		l->port=port;
2364 2432
 		l->proto=proto;
2365 2433
 		l->next=0;
... ...
@@ -2368,6 +2436,54 @@ static struct socket_id* mk_listen_id(char* host, int proto, int port)
2368 2436
 }
2369 2437
 
2370 2438
 
2439
+static void free_name_lst(struct name_lst* lst)
2440
+{
2441
+	struct name_lst* tmp;
2442
+	
2443
+	while(lst){
2444
+		tmp=lst;
2445
+		lst=lst->next;
2446
+		pkg_free(tmp);
2447
+	}
2448
+}
2449
+
2450
+
2451
+static struct socket_id* mk_listen_id2(struct name_lst* addr_l, int proto,
2452
+										int port)
2453
+{
2454
+	struct socket_id* l;
2455
+	l=pkg_malloc(sizeof(struct socket_id));
2456
+	if (l==0) {
2457
+		LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n");
2458
+	} else {
2459
+		l->flags=addr_l->flags;
2460
+		l->port=port;
2461
+		l->proto=proto;
2462
+		l->addr_lst=addr_l;
2463
+		l->next=0;
2464
+	}
2465
+	return l;
2466
+}
2467
+
2468
+
2469
+static void free_socket_id(struct socket_id* i)
2470
+{
2471
+	free_name_lst(i->addr_lst);
2472
+	pkg_free(i);
2473
+}
2474
+
2475
+
2476
+static void free_socket_id_lst(struct socket_id* lst)
2477
+{
2478
+	struct socket_id* tmp;
2479
+	
2480
+	while(lst){
2481
+		tmp=lst;
2482
+		lst=lst->next;
2483
+		free_socket_id(tmp);
2484
+	}
2485
+}
2486
+
2371 2487
 /*
2372 2488
 int main(int argc, char ** argv)
2373 2489
 {
... ...
@@ -89,13 +89,23 @@ union sockaddr_union{
89 89
 
90 90
 
91 91
 enum si_flags { SI_NONE=0, SI_IS_IP=1, SI_IS_LO=2, SI_IS_MCAST=4,
92
-				 SI_IS_ANY=8 };
92
+				 SI_IS_ANY=8, SI_IS_MHOMED=16 };
93
+
94
+struct addr_info{
95
+	str name; /* name - eg.: foo.bar or 10.0.0.1 */
96
+	struct ip_addr address; /*ip address */
97
+	str address_str;        /*ip address converted to string -- optimization*/
98
+	enum si_flags flags; /* SI_IS_IP | SI_IS_LO | SI_IS_MCAST */
99
+	union sockaddr_union su;
100
+	struct addr_info* next;
101
+	struct addr_info* prev;
102
+};
93 103
 
94 104
 struct socket_info{
95 105
 	int socket;
96 106
 	str name; /* name - eg.: foo.bar or 10.0.0.1 */
97 107
 	struct ip_addr address; /* ip address */
98
-	str address_str;        /* ip address converted to string -- optimization*/
108
+	str address_str;        /*ip address converted to string -- optimization*/
99 109
 	str port_no_str; /* port number converted to string -- optimization*/
100 110
 	enum si_flags flags; /* SI_IS_IP | SI_IS_LO | SI_IS_MCAST */
101 111
 	union sockaddr_union su; 
... ...
@@ -103,6 +113,7 @@ struct socket_info{
103 113
 	struct socket_info* prev;
104 114
 	unsigned short port_no;  /* port number */
105 115
 	char proto; /* tcp or udp*/
116
+	struct addr_info* addr_info_lst; /* extra addresses (e.g. SCTP mh) */
106 117
 };
107 118
 
108 119
 
... ...
@@ -135,8 +146,20 @@ struct dest_info{
135 146
 };
136 147
 
137 148
 
138
-struct socket_id{
149
+/* list of names for multi-homed sockets that need to bind on
150
+ * multiple addresses in the same time (sctp ) */
151
+struct name_lst{
139 152
 	char* name;
153
+	struct name_lst* next;
154
+	int flags;
155
+};
156
+
157
+
158
+struct socket_id{
159
+	struct name_lst* addr_lst; /* address list, the first one must
160
+								  be present and is the main one
161
+								  (in case of multihoming sctp)*/
162
+	int flags;
140 163
 	int proto;
141 164
 	int port;
142 165
 	struct socket_id* next;
... ...
@@ -1571,7 +1571,7 @@ try_again:
1571 1571
 					}
1572 1572
 					tmp[tmp_len]=0; /* null terminate the host */
1573 1573
 					/* add a new addr. to our address list */
1574
-					if (add_listen_iface(tmp, port, proto, 0)!=0){
1574
+					if (add_listen_iface(tmp,0,  port, proto, 0)!=0){
1575 1575
 						fprintf(stderr, "failed to add new listen address\n");
1576 1576
 						goto error;
1577 1577
 					}
... ...
@@ -391,6 +391,7 @@ static int fix_actions(struct action* a)
391 391
 	struct hostent* he;
392 392
 	struct ip_addr ip;
393 393
 	struct socket_info* si;
394
+	char buf[30]; /* tmp buffer needed for module param fixups */
394 395
 
395 396
 	if (a==0){
396 397
 		LOG(L_CRIT,"BUG: fix_actions: null pointer\n");
... ...
@@ -506,15 +507,17 @@ static int fix_actions(struct action* a)
506 507
 				if (cmd && cmd->fixup) {
507 508
 					int i;
508 509
 					DBG("fixing %s()\n", cmd->name);
509
-					/* type cast NUMBER to STRING, old modules may expect all STRING params during fixup */
510
+					/* type cast NUMBER to STRING, old modules may expect
511
+					 * all STRING params during fixup */
510 512
 					for (i=0; i<t->val[1].u.number; i++) {
511 513
 						if (t->val[i+2].type == NUMBER_ST) {
512
-							char buf[30];
513
-							snprintf(buf, sizeof(buf)-1, "%ld", t->val[i+2].u.number);
514
-							/* fixup currently requires string pkg_malloc-aed */
514
+							snprintf(buf, sizeof(buf)-1, "%ld", 
515
+										t->val[i+2].u.number);
516
+							/* fixup currently requires string pkg_malloced*/
515 517
 							t->val[i+2].u.string = pkg_malloc(strlen(buf)+1);
516 518
 							if (!t->val[i+2].u.string) {
517
-								LOG(L_CRIT, "ERROR: cannot translate NUMBER to STRING\n");
519
+								LOG(L_CRIT, "ERROR: cannot translate NUMBER"
520
+											" to STRING\n");
518 521
 								return E_OUT_OF_MEM;
519 522
 							}
520 523
 							strcpy(t->val[i+2].u.string, buf);
... ...
@@ -539,11 +542,13 @@ static int fix_actions(struct action* a)
539 542
 								t->val[0].type);
540 543
 					return E_BUG;
541 544
 				}
542
-				he=resolvehost(((struct socket_id*)t->val[0].u.data)->name);
545
+				he=resolvehost(
546
+						((struct socket_id*)t->val[0].u.data)->addr_lst->name
547
+						);
543 548
 				if (he==0){
544 549
 					LOG(L_ERR, "ERROR: fix_actions: force_send_socket:"
545 550
 								" could not resolve %s\n",
546
-							((struct socket_id*)t->val[0].u.data)->name);
551
+						((struct socket_id*)t->val[0].u.data)->addr_lst->name);
547 552
 					return E_BAD_ADDRESS;
548 553
 				}
549 554
 				hostent2ip_addr(&ip, he, 0);
... ...
@@ -552,7 +557,7 @@ static int fix_actions(struct action* a)
552 557
 				if (si==0){
553 558
 					LOG(L_ERR, "ERROR: fix_actions: bad force_send_socket"
554 559
 							" argument: %s:%d (ser doesn't listen on it)\n",
555
-							((struct socket_id*)t->val[0].u.data)->name,
560
+						((struct socket_id*)t->val[0].u.data)->addr_lst->name,
556 561
 							((struct socket_id*)t->val[0].u.data)->port);
557 562
 					return E_BAD_ADDRESS;
558 563
 				}
... ...
@@ -404,7 +404,7 @@ void print_action(struct action* t)
404 404
 		case SOCKID_ST:
405 405
 			DBG("%d:%s:%d",
406 406
 			((struct socket_id*)t->val[0].u.data)->proto,
407
-			ZSW(((struct socket_id*)t->val[0].u.data)->name),
407
+			ZSW(((struct socket_id*)t->val[0].u.data)->addr_lst->name),
408 408
 			((struct socket_id*)t->val[0].u.data)->port
409 409
 			);
410 410
 			break;
... ...
@@ -438,7 +438,7 @@ void print_action(struct action* t)
438 438
 		case SOCKID_ST:
439 439
 			DBG("%d:%s:%d",
440 440
 			((struct socket_id*)t->val[0].u.data)->proto,
441
-			ZSW(((struct socket_id*)t->val[0].u.data)->name),
441
+			ZSW(((struct socket_id*)t->val[0].u.data)->addr_lst->name),
442 442
 			((struct socket_id*)t->val[0].u.data)->port
443 443
 			);
444 444
 			break;
... ...
@@ -470,7 +470,7 @@ void print_action(struct action* t)
470 470
 		case SOCKID_ST:
471 471
 			DBG("%d:%s:%d",
472 472
 			((struct socket_id*)t->val[0].u.data)->proto,
473
-			ZSW(((struct socket_id*)t->val[0].u.data)->name),
473
+			ZSW(((struct socket_id*)t->val[0].u.data)->addr_lst->name),
474 474
 			((struct socket_id*)t->val[0].u.data)->port
475 475
 			);
476 476
 			break;
... ...
@@ -36,6 +36,7 @@
36 36
  *  2004-11-08  added find_si (andrei)
37 37
  *  2007-08-23  added detection for INADDR_ANY types of sockets (andrei)
38 38
  *  2008-08-08  sctp support (andrei)
39
+ *  2008-08-15  support for handling sctp multihomed sockets (andrei)
39 40
  */
40 41
 
41 42
 
... ...
@@ -103,6 +104,28 @@
103 104
 	}while(0)
104 105
 
105 106
 
107
+#define addr_info_listadd sock_listadd
108
+#define addr_info_listins sock_listins
109
+#define addr_info_listrm sock_listrm
110
+
111
+inline static void addr_info_list_ins_lst(struct addr_info* lst,
112
+										struct addr_info* after)
113
+{
114
+	struct addr_info* l;
115
+	struct addr_info* n;
116
+	
117
+	if (lst){
118
+		n=after->next;
119
+		after->next=lst;
120
+		lst->prev=after;
121
+		if (n){
122
+			for(l=lst; l->next; l=l->next);
123
+			l->next=n;
124
+			n->prev=l;
125
+		}
126
+	}
127
+}
128
+
106 129
 
107 130
 /* protocol order, filled by init_proto_order() */
108 131
 enum sip_protos nxt_proto[PROTO_LAST+1]=
... ...
@@ -110,12 +133,102 @@ enum sip_protos nxt_proto[PROTO_LAST+1]=
110 133
 
111 134
 
112 135
 
136
+/* another helper function, it just fills a struct addr_info
137
+ * returns: 0 on success, -1 on error*/
138
+static int init_addr_info(struct addr_info* a,
139
+								char* name, enum si_flags flags)
140
+{
141
+
142
+	memset(a, 0, sizeof(*a));
143
+	a->name.len=strlen(name);
144
+	a->name.s=pkg_malloc(a->name.len+1); /* include \0 */
145
+	if (a->name.s==0) goto error;
146
+	memcpy(a->name.s, name, a->name.len+1);
147
+	a->flags=flags;
148
+	return 0;
149
+error:
150
+	LOG(L_ERR, "ERROR: init_addr_info: memory allocation error\n");
151
+	return -1;
152
+}
153
+
154
+
155
+
156
+/* returns 0 on error, new addr_info_lst element on success */
157
+static inline struct addr_info* new_addr_info(char* name, 
158
+													enum si_flags gf)
159
+{
160
+	struct addr_info* al;
161
+	
162
+	al=pkg_malloc(sizeof(*al));
163
+	if (al==0) goto error;
164
+	al->next=0;
165
+	al->prev=0;
166
+	if (init_addr_info(al, name, gf)!=0) goto error;
167
+	return al;
168
+error:
169
+	LOG(L_ERR, "ERROR: new_addr_info: memory allocation error\n");
170
+	if (al){
171
+		if (al->name.s) pkg_free(al->name.s);
172
+		pkg_free(al);
173
+	}
174
+	return 0;
175
+}
176
+
177
+
178
+
179
+static inline void free_addr_info(struct addr_info* a)
180
+{
181
+	if (a){
182
+		if (a->name.s){
183
+			pkg_free(a->name.s);
184
+			a->name.s=0;
185
+		}
186
+		pkg_free(a);
187
+	}
188
+}
189
+
190
+
191
+
192
+static inline void free_addr_info_lst(struct addr_info** lst)
193
+{
194
+	struct addr_info* a;
195
+	struct addr_info* tmp;
196
+	
197
+	a=*lst;
198
+	while(a){
199
+		tmp=a;
200
+		a=a->next;
201
+		free_addr_info(tmp);
202
+	}
203
+}
204
+
205
+
206
+
207
+/* adds a new add_info_lst element to the corresponding list
208
+ * returns 0 on success, -1 on error */
209
+static int new_addr_info2list(char* name, enum si_flags f,
210
+								struct addr_info** l)
211
+{
212
+	struct addr_info * al;
213
+	
214
+	al=new_addr_info(name, f);
215
+	if (al==0) goto error;
216
+	addr_info_listadd(l, al);
217
+	return 0;
218
+error:
219
+	return -1;
220
+}
221
+
222
+
223
+
113 224
 /* another helper function, it just creates a socket_info struct */
114 225
 static inline struct socket_info* new_sock_info(	char* name,
226
+								struct name_lst* addr_l,
115 227
 								unsigned short port, unsigned short proto,
116 228
 								enum si_flags flags)
117 229
 {
118 230
 	struct socket_info* si;
231
+	struct name_lst* n;
119 232
 	
120 233
 	si=(struct socket_info*) pkg_malloc(sizeof(struct socket_info));
121 234
 	if (si==0) goto error;
... ...
@@ -129,6 +242,13 @@ static inline struct socket_info* new_sock_info(	char* name,
129 242
 	si->port_no=port;
130 243
 	si->proto=proto;
131 244
 	si->flags=flags;
245
+	si->addr_info_lst=0;
246
+	for (n=addr_l; n; n=n->next){
247
+		if (new_addr_info2list(n->name, n->flags, &si->addr_info_lst)!=0){
248
+			LOG(L_ERR, "ERROR: new_sockk_info:new_addr_info2list failed\n");
249
+			goto error;
250
+		}
251
+	}
132 252
 	return si;
133 253
 error:
134 254
 	LOG(L_ERR, "ERROR: new_sock_info: memory allocation error\n");
... ...
@@ -145,6 +265,7 @@ static void free_sock_info(struct socket_info* si)
145 265
 		if(si->name.s) pkg_free(si->name.s);
146 266
 		if(si->address_str.s) pkg_free(si->address_str.s);
147 267
 		if(si->port_no_str.s) pkg_free(si->port_no_str.s);
268
+		if (si->addr_info_lst) free_addr_info_lst(&si->addr_info_lst);
148 269
 	}
149 270
 }
150 271
 
... ...
@@ -204,6 +325,50 @@ static struct socket_info** get_sock_info_list(unsigned short proto)
204 325
 }
205 326
 
206 327
 
328
+/* helper function for grep_sock_info
329
+ * params:
330
+ *  host - hostname to compare with
331
+ *  name - official name
332
+ *  addr_str - name's resolved ip address converted to string
333
+ *  ip_addr - name's ip address 
334
+ *  flags - set to SI_IS_IP if name contains an IP
335
+ *
336
+ * returns 0 if host matches, -1 if not */
337
+inline static int si_hname_cmp(str* host, str* name, str* addr_str, 
338
+								struct ip_addr* ip_addr, int flags)
339
+{
340
+#ifdef USE_IPV6
341
+	struct ip_addr* ip6;
342
+#endif
343
+	
344
+	if ( (host->len==name->len) && 
345
+		(strncasecmp(host->s, name->s, name->len)==0) /*slower*/)
346
+		/* comp. must be case insensitive, host names
347
+		 * can be written in mixed case, it will also match
348
+		 * ipv6 addresses if we are lucky*/
349
+		goto found;
350
+	/* check if host == ip address */
351
+#ifdef USE_IPV6
352
+	/* ipv6 case is uglier, host can be [3ffe::1] */
353
+	ip6=str2ip6(host);
354
+	if (ip6){
355
+		if (ip_addr_cmp(ip6, ip_addr))
356
+			goto found; /* match */
357
+		else
358
+			return -1; /* no match, but this is an ipv6 address
359
+						 so no point in trying ipv4 */
360
+	}
361
+#endif
362
+	/* ipv4 */
363
+	if ( (!(flags&SI_IS_IP)) && (host->len==addr_str->len) && 
364
+			(memcmp(host->s, addr_str->s, addr_str->len)==0) )
365
+		goto found;
366
+	return -1;
367
+found:
368
+	return 0;
369
+}
370
+
371
+
207 372
 /* checks if the proto: host:port is one of the address we listen on
208 373
  * and returns the corresponding socket_info structure.
209 374
  * if port==0, the  port number is ignored
... ...
@@ -215,21 +380,18 @@ static struct socket_info** get_sock_info_list(unsigned short proto)
215 380
 struct socket_info* grep_sock_info(str* host, unsigned short port,
216 381
 												unsigned short proto)
217 382
 {
218
-	char* hname;
219
-	int h_len;
383
+	str hname;
220 384
 	struct socket_info* si;
221 385
 	struct socket_info** list;
386
+	struct addr_info* ai;
222 387
 	unsigned short c_proto;
388
+	
389
+	hname=*host;
223 390
 #ifdef USE_IPV6
224
-	struct ip_addr* ip6;
225
-#endif
226
-	h_len=host->len;
227
-	hname=host->s;
228
-#ifdef USE_IPV6
229
-	if ((h_len>2)&&((*hname)=='[')&&(hname[h_len-1]==']')){
391
+	if ((hname.len>2)&&((*hname.s)=='[')&&(hname.s[hname.len-1]==']')){
230 392
 		/* ipv6 reference, skip [] */
231
-		hname++;
232
-		h_len-=2;
393
+		hname.s++;
394
+		hname.len-=2;
233 395
 	}
234 396
 #endif
235 397
 	c_proto=proto?proto:PROTO_UDP;
... ...
@@ -248,9 +410,9 @@ struct socket_info* grep_sock_info(str* host, unsigned short port,
248 410
 		for (si=*list; si; si=si->next){
249 411
 			DBG("grep_sock_info - checking if host==us: %d==%d && "
250 412
 					" [%.*s] == [%.*s]\n", 
251
-						h_len,
413
+						hname.len,
252 414
 						si->name.len,
253
-						h_len, hname,
415
+						hname.len, hname.s,
254 416
 						si->name.len, si->name.s
255 417
 				);
256 418
 			if (port) {
... ...
@@ -260,32 +422,14 @@ struct socket_info* grep_sock_info(str* host, unsigned short port,
260 422
 					continue;
261 423
 				}
262 424
 			}
263
-			if ( (h_len==si->name.len) && 
264
-				(strncasecmp(hname, si->name.s,
265
-						 si->name.len)==0) /*slower*/)
266
-				/* comp. must be case insensitive, host names
267
-				 * can be written in mixed case, it will also match
268
-				 * ipv6 addresses if we are lucky*/
269
-				goto found;
270
-		/* check if host == ip address */
271
-#ifdef USE_IPV6
272
-			/* ipv6 case is uglier, host can be [3ffe::1] */
273
-			ip6=str2ip6(host);
274
-			if (ip6){
275
-				if (ip_addr_cmp(ip6, &si->address))
276
-					goto found; /* match */
277
-				else
278
-					continue; /* no match, but this is an ipv6 address
279
-								 so no point in trying ipv4 */
280
-			}
281
-#endif
282
-			/* ipv4 */
283
-			if ( 	(!(si->flags&SI_IS_IP)) &&
284
-					(h_len==si->address_str.len) && 
285
-				(memcmp(hname, si->address_str.s, 
286
-									si->address_str.len)==0)
287
-				)
425
+			if (si_hname_cmp(&hname, &si->name, &si->address_str, 
426
+								&si->address, si->flags)==0)
288 427
 				goto found;
428
+			/* try among the extra addresses */
429
+			for (ai=si->addr_info_lst; ai; ai=ai->next)
430
+				if (si_hname_cmp(&hname, &ai->name, &ai->address_str, 
431
+									&ai->address, ai->flags)==0)
432
+					goto found;
289 433
 		}
290 434
 	}while( (proto==0) && (c_proto=next_proto(c_proto)) );
291 435
 not_found:
... ...
@@ -323,8 +467,8 @@ struct socket_info* grep_sock_info_by_port(unsigned short port,
323 467
 			goto not_found; /* false */
324 468
 		}
325 469
 		for (si=*list; si; si=si->next){
326
-			DBG("grep_sock_info_by_port - checking if port %d matches port %d\n", 
327
-					si->port_no, port);
470
+			DBG("grep_sock_info_by_port - checking if port %d matches"
471
+					" port %d\n", si->port_no, port);
328 472
 			if (si->port_no==port) {
329 473
 				goto found;
330 474
 			}
... ...
@@ -352,6 +496,7 @@ struct socket_info* find_si(struct ip_addr* ip, unsigned short port,
352 496
 {
353 497
 	struct socket_info* si;
354 498
 	struct socket_info** list;
499
+	struct addr_info* ai;
355 500
 	unsigned short c_proto;
356 501
 	
357 502
 	c_proto=proto?proto:PROTO_UDP;
... ...
@@ -375,6 +520,9 @@ struct socket_info* find_si(struct ip_addr* ip, unsigned short port,
375 520
 			}
376 521
 			if (ip_addr_cmp(ip, &si->address))
377 522
 				goto found;
523
+			for (ai=si->addr_info_lst; ai; ai=ai->next)
524
+				if (ip_addr_cmp(ip, &ai->address))
525
+					goto found;
378 526
 		}
379 527
 	}while( (proto==0) && (c_proto=next_proto(c_proto)) );
380 528
 not_found:
... ...
@@ -385,43 +533,72 @@ found:
385 533
 
386 534
 
387 535
 
388
-/* adds a new sock_info structure to the corresponding list
389
- * return  0 on success, -1 on error */
390
-int new_sock2list(char* name, unsigned short port, unsigned short proto,
391
-						enum si_flags flags, struct socket_info** list)
536
+/* append a new sock_info structure to the corresponding list
537
+ * return  new sock info on success, 0 on error */
538
+static struct socket_info* new_sock2list(char* name, struct name_lst* addr_l,
539
+									unsigned short port,
540
+									unsigned short proto, enum si_flags flags,
541
+									struct socket_info** list)
392 542
 {
393 543
 	struct socket_info* si;
394 544
 	
395
-	si=new_sock_info(name, port, proto, flags);
545
+	si=new_sock_info(name, addr_l, port, proto, flags);
396 546
 	if (si==0){
397
-		LOG(L_ERR, "ERROR: add_listen_iface: new_sock_info failed\n");
547
+		LOG(L_ERR, "ERROR: new_sock2list: new_sock_info failed\n");
398 548
 		goto error;
399 549
 	}
400 550
 	sock_listadd(list, si);
551
+	return si;
552
+error:
401 553
 	return 0;
554
+}
555
+
556
+
557
+
558
+/* adds a new sock_info structure immediately after "after"
559
+ * return  new sock info on success, 0 on error */
560
+static struct socket_info* new_sock2list_after(char* name,
561
+									struct name_lst* addr_l,
562
+									unsigned short port,
563
+									unsigned short proto, enum si_flags flags,
564
+									struct socket_info* after)
565
+{
566
+	struct socket_info* si;
567
+	
568
+	si=new_sock_info(name, addr_l, port, proto, flags);
569
+	if (si==0){
570
+		LOG(L_ERR, "ERROR: new_sock2list_after: new_sock_info failed\n");
571
+		goto error;
572
+	}
573
+	sock_listins(si, after);
574
+	return si;
402 575
 error:
403
-	return -1;
576
+	return 0;
404 577
 }
405 578
 
406 579
 
407 580
 
408 581
 /* adds a sock_info structure to the corresponding proto list
409 582
  * return  0 on success, -1 on error */
410
-int add_listen_iface(char* name, unsigned short port, unsigned short proto,
583
+int add_listen_iface(char* name, struct name_lst* addr_l,
584
+						unsigned short port, unsigned short proto,
411 585
 						enum si_flags flags)
412 586
 {
413 587
 	struct socket_info** list;
414 588
 	unsigned short c_proto;
589
+	struct name_lst* a_l;
590
+	unsigned short c_port;
415 591
 	
416 592
 	c_proto=(proto)?proto:PROTO_UDP;
417 593
 	do{
418 594
 		list=get_sock_info_list(c_proto);
419 595
 		if (list==0){
420
-			LOG(L_ERR, "ERROR: add_listen_iface: get_sock_info_list failed\n");
596
+			LOG(L_ERR, "ERROR: add_listen_iface: get_sock_info_list"
597
+						" failed\n");
421 598
 			goto error;
422 599
 		}
423 600
 		if (port==0){ /* use default port */
424
-			port=
601
+			c_port=
425 602
 #ifdef USE_TLS
426 603
 				((c_proto)==PROTO_TLS)?tls_port_no:
427 604
 #endif
... ...
@@ -429,13 +606,34 @@ int add_listen_iface(char* name, unsigned short port, unsigned short proto,
429 606
 		}
430 607
 #ifdef USE_TLS
431 608
 		else if ((c_proto==PROTO_TLS) && (proto==0)){
432
-			/* -l  ip:port => on udp:ip:port; tcp:ip:port and tls:ip:port+1? */
433
-			port++;
609
+			/* -l  ip:port => on udp:ip:port; tcp:ip:port and tls:ip:port+1?*/
610
+			c_port=port+1;
434 611
 		}
435 612
 #endif
436
-		if (new_sock2list(name, port, c_proto, flags, list)<0){
437
-			LOG(L_ERR, "ERROR: add_listen_iface: new_sock2list failed\n");
438
-			goto error;
613
+		else{
614
+			c_port=port;
615
+		}
616
+		if (c_proto!=PROTO_SCTP){
617
+			if (new_sock2list(name, 0, c_port, c_proto,
618
+								flags & ~SI_IS_MHOMED, list)==0){
619
+				LOG(L_ERR, "ERROR: add_listen_iface: new_sock2list failed\n");
620
+				goto error;
621
+			}
622
+			/* add the other addresses in the list as separate sockets
623
+			 * since only SCTP can bind to multiple addresses */
624
+			for (a_l=addr_l; a_l; a_l=a_l->next){
625
+				if (new_sock2list(a_l->name, 0, c_port, 
626
+									c_proto, flags & ~SI_IS_MHOMED, list)==0){
627
+					LOG(L_ERR, "ERROR: add_listen_iface: new_sock2list"
628
+								" failed\n");
629
+					goto error;
630
+				}
631
+			}
632
+		}else{
633
+			if (new_sock2list(name, addr_l, c_port, c_proto, flags, list)==0){
634
+				LOG(L_ERR, "ERROR: add_listen_iface: new_sock2list failed\n");
635
+				goto error;
636
+			}
439 637
 		}
440 638
 	}while( (proto==0) && (c_proto=next_proto(c_proto)));
441 639
 	return 0;
... ...
@@ -452,7 +650,7 @@ error:
452 650
  */
453 651
 int add_interfaces(char* if_name, int family, unsigned short port,
454 652
 					unsigned short proto,
455
-					struct socket_info** list)
653
+					struct addr_info** ai_l)
456 654
 {
457 655
 	struct ifconf ifc;
458 656
 	struct ifreq ifr;
... ...
@@ -552,9 +750,10 @@ int add_interfaces(char* if_name, int family, unsigned short port,
552 750
 			/* check if loopback */
553 751
 			if (ifrcopy.ifr_flags & IFF_LOOPBACK) 
554 752
 				flags|=SI_IS_LO;
555
-			/* add it to one of the lists */
556
-			if (new_sock2list(tmp, port, proto, flags, list)!=0){
557
-				LOG(L_ERR, "ERROR: add_interfaces: new_sock2list failed\n");
753
+			/* save the info */
754
+			if (new_addr_info2list(tmp, flags, ai_l)!=0){
755
+				LOG(L_ERR, "ERROR: add_interfaces: "
756
+						"new_addr_info2list failed\n");
558 757
 				goto error;
559 758
 			}
560 759
 			ret=0;
... ...
@@ -578,30 +777,229 @@ error:
578 777
 
579 778
 
580 779
 
780
+/* internal helper function: resolve host names and add aliases
781
+ * name is a value result parameter: it should contain the hostname that
782
+ * will be used to fill all the other members, including name itself
783
+ * in some situation (name->s should be a 0 terminated pkg_malloc'ed string)
784
+ * return 0 on success and -1 on error */
785
+static int fix_hostname(str* name, struct ip_addr* address, str* address_str,
786
+						enum si_flags* flags, int* type_flags,
787
+						struct socket_info* s)
788
+{
789
+	struct hostent* he;
790
+	char* tmp;
791
+	char** h;
792
+	
793
+	/* get "official hostnames", all the aliases etc. */
794
+	he=resolvehost(name->s);
795
+	if (he==0){
796
+		LOG(L_ERR, "ERROR: fix_hostname: could not resolve %s\n", name->s);
797
+		goto error;
798
+	}
799
+	/* check if we got the official name */
800
+	if (strcasecmp(he->h_name, name->s)!=0){
801
+		if (add_alias(name->s, name->len, s->port_no, s->proto)<0){
802
+			LOG(L_ERR, "ERROR: fix_hostname: add_alias failed\n");
803
+		}
804
+		/* change the official name */
805
+		pkg_free(name->s);
806
+		name->s=(char*)pkg_malloc(strlen(he->h_name)+1);
807
+		if (name->s==0){
808
+			LOG(L_ERR,  "ERROR: fix_hostname: out of memory.\n");
809
+			goto error;
810
+		}
811
+		name->len=strlen(he->h_name);
812
+		strncpy(name->s, he->h_name, name->len+1);
813
+	}
814
+	/* add the aliases*/
815
+	for(h=he->h_aliases; h && *h; h++)
816
+		if (add_alias(*h, strlen(*h), s->port_no, s->proto)<0){
817
+				LOG(L_ERR, "ERROR: fix_hostname: add_alias failed\n");
818
+		}
819
+	hostent2ip_addr(address, he, 0); /*convert to ip_addr format*/
820
+	if (type_flags){
821
+		*type_flags|=(address->af==AF_INET)?SOCKET_T_IPV4:SOCKET_T_IPV6;
822
+	}
823
+	if ((tmp=ip_addr2a(address))==0) goto error;
824
+	address_str->s=pkg_malloc(strlen(tmp)+1);
825
+	if (address_str->s==0){
826
+		LOG(L_ERR, "ERROR: fix_hostname: out of memory.\n");
827
+		goto error;
828
+	}
829
+	strncpy(address_str->s, tmp, strlen(tmp)+1);
830
+	/* set is_ip (1 if name is an ip address, 0 otherwise) */
831
+	address_str->len=strlen(tmp);
832
+	if ((address_str->len==name->len) &&
833
+		(strncasecmp(address_str->s, name->s, address_str->len)==0)){
834
+		*flags|=SI_IS_IP;
835
+		/* do rev. DNS on it (for aliases)*/
836
+		he=rev_resolvehost(address);
837
+		if (he==0){
838
+			LOG(L_WARN, "WARNING: fix_hostname: could not rev. resolve %s\n",
839
+					name->s);
840
+		}else{
841
+			/* add the aliases*/
842
+			if (add_alias(he->h_name, strlen(he->h_name), s->port_no,
843
+							s->proto)<0){
844
+				LOG(L_ERR, "ERROR: fix_hostname: add_alias failed\n");
845
+			}
846
+			for(h=he->h_aliases; h && *h; h++)
847
+				if (add_alias(*h, strlen(*h), s->port_no, s->proto) < 0){
848
+					LOG(L_ERR, "ERROR: fix_hostname: add_alias failed\n");
849
+				}
850
+		}
851
+	}
852
+	
853
+#ifdef USE_MCAST
854
+	/* Check if it is an multicast address and
855
+	 * set the flag if so
856
+	 */
857
+	if (is_mcast(address)){
858
+		*flags |= SI_IS_MCAST;
859
+	}
860
+#endif /* USE_MCAST */
861
+	
862
+	/* check if INADDR_ANY */
863
+	if (ip_addr_any(address))
864
+		*flags|=SI_IS_ANY;
865
+	
866
+	return 0;
867
+error:
868
+	return -1;
869
+}
870
+
871
+
872
+
873
+/* append new elements to a socket_info list after "list"
874
+ * each element is created  from addr_info_lst + port, protocol and flags
875
+ * return 0 on succes, -1 on error
876
+ */
877
+static int addr_info_to_si_lst(struct addr_info* ai_lst, unsigned short port,
878
+								char proto, enum si_flags flags,
879
+								struct socket_info** list)
880
+{
881
+	struct addr_info* ail;
882
+	
883
+	for (ail=ai_lst; ail; ail=ail->next){
884
+		if(new_sock2list(ail->name.s, 0, port_no, proto, ail->flags | flags,
885
+							list)==0)
886
+			return -1;
887
+	}
888
+	return 0;
889
+}
890
+
891
+
892
+
893
+/* insert new elements to a socket_info list after "el", 
894
+ * each element is created from addr_info_lst + port, * protocol and flags
895
+ * return 0 on succes, -1 on error
896
+ */
897
+static int addr_info_to_si_lst_after(struct addr_info* ai_lst,
898
+										unsigned short port,
899
+										char proto, enum si_flags flags,
900
+										struct socket_info* el)
901
+{
902
+	struct addr_info* ail;
903
+	struct socket_info* new_si;
904
+	
905
+	for (ail=ai_lst; ail; ail=ail->next){
906
+		if((new_si=new_sock2list_after(ail->name.s, 0, port_no, proto,
907
+								ail->flags | flags, el))==0)
908
+			return -1;
909
+		el=new_si;
910
+	}
911
+	return 0;
912
+}
913
+
914
+
915
+
581 916
 /* fixes a socket list => resolve addresses, 
582 917
  * interface names, fills missing members, remove duplicates
583 918
  * fills type_flags if not null with SOCKET_T_IPV4 and/or SOCKET_T_IPV6*/
584 919
 static int fix_socket_list(struct socket_info **list, int* type_flags)
585 920
 {
586 921
 	struct socket_info* si;
922
+	struct socket_info* new_si;
587 923
 	struct socket_info* l;
588 924
 	struct socket_info* next;
925
+	struct socket_info* next_si;
926
+	struct socket_info* del_si;
927
+	struct socket_info* keep_si;
589 928
 	char* tmp;
590 929
 	int len;
591
-	struct hostent* he;
592
-	char** h;
593
-	
930
+	struct addr_info* ai_lst;
931
+	struct addr_info* ail;
932
+	struct addr_info* tmp_ail;
933
+	struct addr_info* tmp_ail_next;
934
+	struct addr_info* ail_next;
935
+
594 936
 	if (type_flags)
595 937
 		*type_flags=0;
596 938
 	/* try to change all the interface names into addresses
597 939
 	 *  --ugly hack */
598 940
 	for (si=*list;si;){
599 941
 		next=si->next;
942
+		ai_lst=0;
600 943
 		if (add_interfaces(si->name.s, AF_INET, si->port_no,
601
-							si->proto, list)!=-1){
944
+							si->proto, &ai_lst)!=-1){
945
+			if (si->flags & SI_IS_MHOMED){
946
+				if((new_si=new_sock2list_after(ai_lst->name.s, 0, si->port_no,
947
+											si->proto,
948
+											ai_lst->flags|si->flags, si))==0)
949
+					break;
950
+				ail=ai_lst;
951
+				ai_lst=ai_lst->next;
952
+				free_addr_info(ail); /* free the first elem. */
953
+				if (ai_lst){
954
+					ai_lst->prev=0;
955
+					/* find the end */
956
+					for (ail=ai_lst; ail->next; ail=ail->next);
957
+					/* add the mh list after the last position in ai_lst */
958
+					addr_info_list_ins_lst(si->addr_info_lst, ail);
959
+					new_si->addr_info_lst=ai_lst;
960
+					si->addr_info_lst=0; /* detached and moved to new_si */
961
+					ail=ail->next; /* ail== old si->addr_info_lst */
962
+				}else{
963
+					ail=si->addr_info_lst;
964
+					new_si->addr_info_lst=ail;
965
+					si->addr_info_lst=0; /* detached and moved to new_si */
966
+				}
967
+				
968
+			}else{
969
+				/* add all addr. as separate  interfaces */
970
+				if (addr_info_to_si_lst_after(ai_lst, si->port_no, si->proto,
971
+						 						si->flags, si)!=0)
972
+					goto error;
973
+				/* ai_lst not needed anymore */
974
+				free_addr_info_lst(&ai_lst);
975
+				ail=0;
976
+				new_si=0;
977
+			}
602 978
 			/* success => remove current entry (shift the entire array)*/
603 979
 			sock_listrm(list, si);
604 980
 			free_sock_info(si);
981
+		}else{
982
+			new_si=si;
983
+			ail=si->addr_info_lst;
984
+		}
985
+		
986
+		if (ail){
987
+			if (new_si && (new_si->flags & SI_IS_MHOMED)){
988
+				ai_lst=0;
989
+				for (; ail;){
990
+					ail_next=ail->next;
991
+					if (add_interfaces(ail->name.s, AF_INET, new_si->port_no,
992
+											new_si->proto, &ai_lst)!=-1){
993
+						/* add the resolved list after the current position */
994
+						addr_info_list_ins_lst(ai_lst, ail);
995
+						/* success, remove the current entity */
996
+						addr_info_listrm(&new_si->addr_info_lst, ail);
997
+						free_addr_info(ail);
998
+						ai_lst=0;
999
+					}
1000
+					ail=ail_next;
1001
+				}
1002
+			}
605 1003
 		}
606 1004
 		si=next;
607 1005
 	}
... ...
@@ -632,87 +1030,16 @@ static int fix_socket_list(struct socket_info **list, int* type_flags)
632 1030
 		strncpy(si->port_no_str.s, tmp, len+1);
633 1031
 		si->port_no_str.len=len;
634 1032
 		
635
-		/* get "official hostnames", all the aliases etc. */
636
-		he=resolvehost(si->name.s);
637
-		if (he==0){
638
-			LOG(L_ERR, "ERROR: fix_socket_list: could not resolve %s\n",
639
-					si->name.s);
1033
+		if (fix_hostname(&si->name, &si->address, &si->address_str,
1034
+						&si->flags, type_flags, si) !=0 )
640 1035
 			goto error;
641
-		}
642
-		/* check if we got the official name */
643
-		if (strcasecmp(he->h_name, si->name.s)!=0){
644
-			if (add_alias(si->name.s, si->name.len,
645
-							si->port_no, si->proto)<0){
646
-				LOG(L_ERR, "ERROR: fix_socket_list: add_alias failed\n");
647
-			}
648
-			/* change the official name */
649
-			pkg_free(si->name.s);
650
-			si->name.s=(char*)pkg_malloc(strlen(he->h_name)+1);
651
-			if (si->name.s==0){
652
-				LOG(L_ERR,  "ERROR: fix_socket_list: out of memory.\n");
1036
+		/* fix hostnames in mh addresses */
1037
+		for (ail=si->addr_info_lst; ail; ail=ail->next){
1038
+			if (fix_hostname(&ail->name, &ail->address, &ail->address_str,
1039
+						&ail->flags, type_flags, si) !=0 )
653 1040
 				goto error;
654
-			}
655
-			si->name.len=strlen(he->h_name);
656
-			strncpy(si->name.s, he->h_name, si->name.len+1);
657 1041
 		}
658
-		/* add the aliases*/
659
-		for(h=he->h_aliases; h && *h; h++)
660
-			if (add_alias(*h, strlen(*h), si->port_no, si->proto)<0){
661
-				LOG(L_ERR, "ERROR: fix_socket_list: add_alias failed\n");
662
-			}
663
-		hostent2ip_addr(&si->address, he, 0); /*convert to ip_addr 
664
-														 format*/
665
-		if (type_flags){
666
-			*type_flags|=(si->address.af==AF_INET)?SOCKET_T_IPV4:SOCKET_T_IPV6;
667
-		}
668
-		if ((tmp=ip_addr2a(&si->address))==0) goto error;
669
-		si->address_str.s=(char*)pkg_malloc(strlen(tmp)+1);
670
-		if (si->address_str.s==0){
671
-			LOG(L_ERR, "ERROR: fix_socket_list: out of memory.\n");
672
-			goto error;
673
-		}
674
-		strncpy(si->address_str.s, tmp, strlen(tmp)+1);
675
-		/* set is_ip (1 if name is an ip address, 0 otherwise) */
676
-		si->address_str.len=strlen(tmp);
677
-		if 	(	(si->address_str.len==si->name.len)&&
678
-				(strncasecmp(si->address_str.s, si->name.s,
679
-								si->address_str.len)==0)
680
-			){
681
-				si->flags|=SI_IS_IP;
682
-				/* do rev. DNS on it (for aliases)*/
683
-				he=rev_resolvehost(&si->address);
684
-				if (he==0){
685
-					LOG(L_WARN, "WARNING: fix_socket_list:"
686
-							" could not rev. resolve %s\n",
687
-							si->name.s);
688
-				}else{
689
-					/* add the aliases*/
690
-					if (add_alias(he->h_name, strlen(he->h_name),
691
-									si->port_no, si->proto)<0){
692
-						LOG(L_ERR, "ERROR: fix_socket_list:"
693
-									"add_alias failed\n");
694
-					}
695
-					for(h=he->h_aliases; h && *h; h++)
696
-						if (add_alias(*h,strlen(*h),si->port_no,si->proto)<0){
697
-							LOG(L_ERR, "ERROR: fix_socket_list:"
698
-									" add_alias failed\n");
699
-						}
700
-				}
701
-		}
702
-
703
-#ifdef USE_MCAST
704
-		     /* Check if it is an multicast address and
705
-		      * set the flag if so
706
-		      */
707
-		if (is_mcast(&si->address)) {
708
-			si->flags |= SI_IS_MCAST;
709
-		}
710
-#endif /* USE_MCAST */
711 1042
 		
712
-		/* check if INADDR_ANY */
713
-		if (ip_addr_any(&si->address))
714
-			si->flags|=SI_IS_ANY;
715
-
716 1043
 #ifdef EXTRA_DEBUG
717 1044
 		printf("              %.*s [%s]:%s%s\n", si->name.len, 
718 1045
 				si->name.s, si->address_str.s, si->port_no_str.s,
... ...
@@ -720,51 +1047,191 @@ static int fix_socket_list(struct socket_info **list, int* type_flags)
720 1047
 #endif
721 1048
 	}
722 1049
 	/* removing duplicate addresses*/
723
-	for (si=*list;si; si=si->next){
1050
+	for (si=*list;si; ){
1051
+		next_si=si->next;
724 1052
 		for (l=si->next;l;){
725 1053
 			next=l->next;
726 1054
 			if ((si->port_no==l->port_no) &&
727 1055
 				(si->address.af==l->address.af) &&
728
-				(memcmp(si->address.u.addr, l->address.u.addr, si->address.len)
729
-					== 0)
1056
+				(memcmp(si->address.u.addr, l->address.u.addr,
1057
+						si->address.len) == 0)
730 1058
 				){
1059
+				/* remove the socket with no  extra addresses.,
1060
+				 * if both of them have extra addresses, remove one of them
1061
+				 * and merge the extra addresses into the other */
1062
+				if (l->addr_info_lst==0){
1063
+					del_si=l;
1064
+					keep_si=si;
1065
+				}else if (si->addr_info_lst==0){
1066
+					del_si=si;
1067
+					keep_si=l;
1068
+				}else{
1069
+					/* move l->addr_info_lst to si->addr_info_lst */
1070
+					/* find last elem */
1071
+					for (ail=si->addr_info_lst; ail->next; ail=ail->next);
1072
+					/* add the l list after the last position in si lst */
1073
+					addr_info_list_ins_lst(l->addr_info_lst, ail);
1074
+					l->addr_info_lst=0; /* detached */
1075
+					del_si=l; /* l will be removed */
1076
+					keep_si=l;
1077
+				}
731 1078
 #ifdef EXTRA_DEBUG
732 1079
 				printf("removing duplicate %s [%s] ==  %s [%s]\n",
733
-						si->name.s, si->address_str.s,
734
-						 l->name.s, l->address_str.s);
1080
+						keep_si->name.s, keep_si->address_str.s,
1081
+						 del_si->name.s, del_si->address_str.s);
735 1082
 #endif
736 1083
 				/* add the name to the alias list*/
737
-				if ((!(l->flags& SI_IS_IP)) && (
738
-						(l->name.len!=si->name.len)||
739
-						(strncmp(l->name.s, si->name.s, si->name.len)!=0))
1084
+				if ((!(del_si->flags& SI_IS_IP)) && (
1085
+						(del_si->name.len!=keep_si->name.len)||
1086
+						(strncmp(del_si->name.s, keep_si->name.s,
1087
+								 del_si->name.len)!=0))
740 1088
 					)
741
-					add_alias(l->name.s, l->name.len, l->port_no, l->proto);
1089
+					add_alias(del_si->name.s, del_si->name.len,
1090
+								l->port_no, l->proto);
742 1091
 						
743
-				/* remove l*/
744
-				sock_listrm(list, l);
745
-				free_sock_info(l);
1092
+				/* remove del_si*/
1093
+				sock_listrm(list, del_si);
1094
+				free_sock_info(del_si);
746 1095
 			}
747 1096
 			l=next;
748 1097
 		}
1098
+		si=next_si;
1099
+	}
1100
+	/* check for duplicates in extra_addresses */
1101
+	for (si=*list;si; si=si->next){
1102
+		/* check  for & remove internal duplicates: */
1103
+		for (ail=si->addr_info_lst; ail;){
1104
+			ail_next=ail->next;
1105
+			/* 1. check if the extra addresses contain a duplicate for the 
1106
+			 * main  one */
1107
+			if ((ail->address.af==si->address.af) &&
1108
+				(memcmp(ail->address.u.addr, si->address.u.addr,
1109
+							ail->address.len) == 0)){
1110
+				/* add the name to the alias list*/
1111
+				if ((!(ail->flags& SI_IS_IP)) && (
1112
+					(ail->name.len!=si->name.len)||
1113
+					(strncmp(ail->name.s, si->name.s, ail->name.len)!=0)))
1114
+					add_alias(ail->name.s, ail->name.len, si->port_no,
1115
+								si->proto);
1116
+					/* remove ail*/
1117
+				addr_info_listrm(&si->addr_info_lst, ail);
1118
+				free_addr_info(ail);
1119
+				ail=ail_next;
1120
+				continue;
1121
+			}
1122
+			/* 2. check if the extra addresses contain a duplicates for 
1123
+			 *  other addresses in the same list */
1124
+			for (tmp_ail=ail->next; tmp_ail;){
1125
+				tmp_ail_next=tmp_ail->next;
1126
+				if ((ail->address.af==tmp_ail->address.af) &&
1127
+					(memcmp(ail->address.u.addr, tmp_ail->address.u.addr,
1128
+							ail->address.len) == 0)){
1129
+					/* add the name to the alias list*/
1130
+					if ((!(tmp_ail->flags& SI_IS_IP)) && (
1131
+						(ail->name.len!=tmp_ail->name.len)||
1132
+						(strncmp(ail->name.s, tmp_ail->name.s,
1133
+										tmp_ail->name.len)!=0))
1134
+						)
1135
+						add_alias(tmp_ail->name.s, tmp_ail->name.len,
1136
+									si->port_no, si->proto);
1137
+						/* remove tmp_ail*/
1138
+					addr_info_listrm(&si->addr_info_lst, tmp_ail);
1139
+					free_addr_info(tmp_ail);
1140
+				}
1141
+				tmp_ail=tmp_ail_next;
1142
+			}
1143
+			ail=ail_next;
1144
+		}
1145
+		/* check for duplicates between extra addresses (e.g. sctp MH)
1146
+		 * and other main addresses, on conflict remove the corresponding
1147
+		 * extra addresses (another possible solution would be to join
1148
+		 * the 2 si entries into one). */
1149
+		for (ail=si->addr_info_lst; ail;){
1150
+			ail_next=ail->next;
1151
+			for (l=*list;l; l=l->next){
1152
+				if (l==si) continue;
1153
+				if (si->port_no==l->port_no){
1154
+					if ((ail->address.af==l->address.af) &&
1155
+						(memcmp(ail->address.u.addr, l->address.u.addr,
1156
+										ail->address.len) == 0)){
1157
+						/* add the name to the alias list*/
1158
+						if ((!(ail->flags& SI_IS_IP)) && (
1159
+							(ail->name.len!=l->name.len)||
1160
+							(strncmp(ail->name.s, l->name.s, l->name.len)!=0))
1161
+							)
1162
+							add_alias(ail->name.s, ail->name.len,
1163
+										l->port_no, l->proto);
1164
+						/* remove ail*/
1165
+						addr_info_listrm(&si->addr_info_lst, ail);
1166
+						free_addr_info(ail);
1167
+						break;
1168
+					}
1169
+					/* check for duplicates with other  extra addresses
1170
+					 * lists */
1171
+					for (tmp_ail=l->addr_info_lst; tmp_ail; ){
1172
+						tmp_ail_next=tmp_ail->next;
1173
+						if ((ail->address.af==tmp_ail->address.af) &&
1174
+							(memcmp(ail->address.u.addr,
1175
+									tmp_ail->address.u.addr,
1176
+									ail->address.len) == 0)){
1177
+							/* add the name to the alias list*/
1178
+							if ((!(tmp_ail->flags& SI_IS_IP)) && (
1179
+									(ail->name.len!=tmp_ail->name.len)||
1180
+									(strncmp(ail->name.s, tmp_ail->name.s,
1181
+											tmp_ail->name.len)!=0))
1182
+								)
1183
+								add_alias(tmp_ail->name.s, tmp_ail->name.len,
1184
+										l->port_no, l->proto);
1185
+							/* remove tmp_ail*/
1186
+							addr_info_listrm(&l->addr_info_lst, tmp_ail);
1187
+							free_addr_info(tmp_ail);
1188
+						}
1189
+						tmp_ail=tmp_ail_next;
1190
+					}
1191
+				}
1192
+			}
1193
+			ail=ail_next;
1194
+		}
749 1195
 	}
750 1196
 
751 1197
 #ifdef USE_MCAST
752 1198
 	     /* Remove invalid multicast entries */
753 1199
 	si=*list;
754 1200
 	while(si){
755
-		if ((si->flags & SI_IS_MCAST) && 
756
-		    ((si->proto == PROTO_TCP)
1201
+		if ((si->proto == PROTO_TCP)
757 1202
 #ifdef USE_TLS
758 1203
 		    || (si->proto == PROTO_TLS)
759 1204
 #endif /* USE_TLS */
760
-		    )){
761
-			LOG(L_WARN, "WARNING: removing entry %s:%s [%s]:%s\n",
762
-			    get_proto_name(si->proto), si->name.s, 
763
-			    si->address_str.s, si->port_no_str.s);
764
-			l = si;
765
-			si=si->next;
766
-			sock_listrm(list, l);
767
-			free_sock_info(l);
1205
+#ifdef USE_SCTP
1206
+			|| (si->proto == PROTO_SCTP)
1207
+#endif
1208
+			){
1209
+			if (si->flags & SI_IS_MCAST){
1210
+				LOG(L_WARN, "WARNING: removing entry %s:%s [%s]:%s\n",
1211
+					get_proto_name(si->proto), si->name.s, 
1212
+					si->address_str.s, si->port_no_str.s);
1213
+				l = si;
1214
+				si=si->next;
1215
+				sock_listrm(list, l);
1216
+				free_sock_info(l);
1217
+			}else{
1218
+				ail=si->addr_info_lst;
1219
+				while(ail){
1220
+					if (ail->flags & SI_IS_MCAST){
1221
+						LOG(L_WARN, "WARNING: removing mh entry %s:%s"
1222
+								" [%s]:%s\n",
1223
+								get_proto_name(si->proto), ail->name.s, 
1224
+								ail->address_str.s, si->port_no_str.s);
1225
+						tmp_ail=ail;
1226
+						ail=ail->next;
1227
+						addr_info_listrm(&si->addr_info_lst, tmp_ail);
1228
+						free_addr_info(tmp_ail);
1229
+					}else{
1230
+						ail=ail->next;
1231
+					}
1232
+				}
1233
+				si=si->next;
1234
+			}
768 1235
 		} else {
769 1236
 			si=si->next;
770 1237
 		}
... ...
@@ -784,6 +1251,9 @@ int fix_all_socket_lists()
784 1251
 {
785 1252
 	struct utsname myname;
786 1253
 	int flags;
1254
+	struct addr_info* ai_lst;
1255
+	
1256
+	ai_lst=0;
787 1257
 	
788 1258
 	if ((udp_listen==0)
789 1259
 #ifdef USE_TCP
... ...
@@ -797,26 +1267,40 @@ int fix_all_socket_lists()
797 1267
 #endif
798 1268
 		){
799 1269
 		/* get all listening ipv4 interfaces */
800
-		if (add_interfaces(0, AF_INET, 0,  PROTO_UDP, &udp_listen)==0){
1270
+		if ((add_interfaces(0, AF_INET, 0,  PROTO_UDP, &ai_lst)==0) &&
1271
+			(addr_info_to_si_lst(ai_lst, 0, PROTO_UDP, 0, &udp_listen)==0)){
1272
+			free_addr_info_lst(&ai_lst);
1273
+			ai_lst=0;
801 1274
 			/* if ok, try to add the others too */
802 1275
 #ifdef USE_TCP
803 1276
 			if (!tcp_disable){
804
-				if (add_interfaces(0, AF_INET, 0,  PROTO_TCP, &tcp_listen)!=0)
1277
+				if ((add_interfaces(0, AF_INET, 0,  PROTO_TCP, &ai_lst)!=0) ||
1278
+					(addr_info_to_si_lst(ai_lst, 0, PROTO_TCP, 0,
1279
+										 				&tcp_listen)!=0))
805 1280
 					goto error;
1281
+				free_addr_info_lst(&ai_lst);
1282
+				ai_lst=0;
806 1283
 #ifdef USE_TLS
807 1284
 				if (!tls_disable){
808
-					if (add_interfaces(0, AF_INET, 0, PROTO_TLS,
809
-								&tls_listen)!=0)
810
-					goto error;
1285
+					if ((add_interfaces(0, AF_INET, 0, PROTO_TLS,
1286
+										&ai_lst)!=0) ||
1287
+						(addr_info_to_si_lst(ai_lst, 0, PROTO_TLS, 0,
1288
+										 				&tls_listen)!=0))
1289
+						goto error;
811 1290
 				}
1291
+				free_addr_info_lst(&ai_lst);
1292
+				ai_lst=0;
812 1293
 #endif
813 1294
 			}