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 186
 
187 187
 static void warn(char* s);
188 188
 static struct socket_id* mk_listen_id(char*, int, int);
189
+static struct name_lst* mk_name_lst(char* name, int flags);
190
+static struct socket_id* mk_listen_id2(struct name_lst*, int, int);
191
+static void free_name_lst(struct name_lst* lst);
192
+static void free_socket_id_lst(struct socket_id* i);
189 193
 
190 194
 %}
191 195
 
... ...
@@ -198,6 +203,7 @@ static struct socket_id* mk_listen_id(char*, int, int);
198 198
 	struct net* ipnet;
199 199
 	struct ip_addr* ipaddr;
200 200
 	struct socket_id* sockid;
201
+	struct name_lst* name_l;
201 202
 	struct avp_spec* attr;
202 203
 	select_t* select;
203 204
 }
... ...
@@ -466,8 +472,11 @@ static struct socket_id* mk_listen_id(char*, int, int);
466 466
 %type <ipnet> ipnet
467 467
 %type <strval> host
468 468
 %type <strval> listen_id
469
+%type <name_l> listen_id_lst
470
+%type <name_l> listen_id2
469 471
 %type <sockid>  id_lst
470 472
 %type <sockid>  phostport
473
+%type <sockid>  listen_phostport
471 474
 %type <intval> proto port
472 475
 %type <intval> equalop strop intop binop
473 476
 %type <strval> host_sep
... ...
@@ -550,6 +559,20 @@ listen_id:
550 550
 		}
551 551
 	}
552 552
 	;
553
+
554
+
555
+listen_id_lst:
556
+	listen_id	{ $$=mk_name_lst($1, SI_IS_MHOMED); }
557
+	| listen_id COMMA listen_id_lst	{ $$=mk_name_lst($1, SI_IS_MHOMED); 
558
+										if ($$) $$->next=$3;
559
+									}
560
+	;
561
+
562
+listen_id2:
563
+	LPAREN listen_id_lst RPAREN { $$=$2; }
564
+	| listen_id	{ $$=mk_name_lst($1, 0); }
565
+	;
566
+
553 567
 proto:
554 568
 	UDP	{ $$=PROTO_UDP; }
555 569
 	| TCP	{ $$=PROTO_TCP; }
... ...
@@ -568,9 +591,18 @@ phostport:
568 568
 	| proto COLON listen_id COLON port	{ $$=mk_listen_id($3, $1, $5);}
569 569
 	| listen_id COLON error { $$=0; yyerror(" port number expected"); }
570 570
 	;
571
+
572
+listen_phostport:
573
+	listen_id2		{ $$=mk_listen_id2($1, 0, 0); }
574
+	| listen_id2 COLON port	{ $$=mk_listen_id2($1, 0, $3); }
575
+	| proto COLON listen_id2	{ $$=mk_listen_id2($3, $1, 0); }
576
+	| proto COLON listen_id2 COLON port	{ $$=mk_listen_id2($3, $1, $5);}
577
+	| listen_id2 COLON error { $$=0; yyerror(" port number expected"); }
578
+	;
579
+
571 580
 id_lst:
572
-	phostport		{  $$=$1 ; }
573
-	| phostport id_lst	{ $$=$1; $$->next=$2; }
581
+	listen_phostport		{  $$=$1 ; }
582
+	| listen_phostport id_lst	{ $$=$1; $$->next=$2; }
574 583
 	;
575 584
 
576 585
 flags_decl:		FLAGS_DECL	flag_list
... ...
@@ -1107,16 +1139,28 @@ assign_stm:
1107 1107
 	| REPLY_TO_VIA EQUAL error { yyerror("boolean value expected"); }
1108 1108
 	| LISTEN EQUAL id_lst {
1109 1109
 		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");
1110
+			if (add_listen_iface(	lst_tmp->addr_lst->name,
1111
+									lst_tmp->addr_lst->next,
1112
+									lst_tmp->port, lst_tmp->proto,
1113
+									lst_tmp->flags)!=0) {
1114
+				LOG(L_CRIT,  "ERROR: cfg. parser: failed to add listen"
1115
+								" address\n");
1112 1116
 				break;
1113 1117
 			}
1114 1118
 		}
1119
+		free_socket_id_lst($3);
1115 1120
 	}
1116 1121
 	| LISTEN EQUAL  error { yyerror("ip address or hostname expected"); }
1117 1122
 	| 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);
1123
+		for(lst_tmp=$3; lst_tmp; lst_tmp=lst_tmp->next){
1124
+			add_alias(	lst_tmp->addr_lst->name,
1125
+						strlen(lst_tmp->addr_lst->name),
1126
+						lst_tmp->port, lst_tmp->proto);
1127
+			for (nl_tmp=lst_tmp->addr_lst->next; nl_tmp; nl_tmp=nl_tmp->next)
1128
+				add_alias(nl_tmp->name, strlen(nl_tmp->name),
1129
+							lst_tmp->port, lst_tmp->proto);
1130
+		}
1131
+		free_socket_id_lst($3);
1120 1132
 	}
1121 1133
 	| ALIAS  EQUAL error  { yyerror(" hostname expected"); }
1122 1134
 	| ADVERTISED_ADDRESS EQUAL listen_id {
... ...
@@ -2289,8 +2333,12 @@ cmd:
2289 2289
 	}
2290 2290
 	| SET_ADV_PORT LPAREN error RPAREN { $$=0; yyerror("bad argument, string expected"); }
2291 2291
 	| 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"); }
2292
+	| FORCE_SEND_SOCKET LPAREN phostport RPAREN { 
2293
+		$$=mk_action(FORCE_SEND_SOCKET_T, 1, SOCKID_ST, $3);
2294
+	}
2295
+	| FORCE_SEND_SOCKET LPAREN error RPAREN {
2296
+		$$=0; yyerror("bad argument, [proto:]host[:port] expected");
2297
+	}
2294 2298
 	| FORCE_SEND_SOCKET error {$$=0; yyerror("missing '(' or ')' ?"); }
2295 2299
 	| ID {mod_func_action = mk_action(MODULE_T, 2, MODEXP_ST, NULL, NUMBER_ST, 0); } LPAREN func_params RPAREN	{
2296 2300
 		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 2352
 }
2353 2353
 
2354 2354
 
2355
+static struct name_lst* mk_name_lst(char* host, int flags)
2356
+{
2357
+	struct name_lst* l;
2358
+	l=pkg_malloc(sizeof(struct name_lst));
2359
+	if (l==0) {
2360
+		LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n");
2361
+	} else {
2362
+		l->name=host;
2363
+		l->flags=flags;
2364
+		l->next=0;
2365
+	}
2366
+	return l;
2367
+}
2368
+
2369
+
2355 2370
 static struct socket_id* mk_listen_id(char* host, int proto, int port)
2356 2371
 {
2357 2372
 	struct socket_id* l;
... ...
@@ -2359,7 +2422,12 @@ static struct socket_id* mk_listen_id(char* host, int proto, int port)
2359 2359
 	if (l==0) {
2360 2360
 		LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n");
2361 2361
 	} else {
2362
-		l->name=host;
2362
+		l->addr_lst=mk_name_lst(host, 0);
2363
+		if (l->addr_lst==0){
2364
+			pkg_free(l);
2365
+			return 0;
2366
+		}
2367
+		l->flags=0;
2363 2368
 		l->port=port;
2364 2369
 		l->proto=proto;
2365 2370
 		l->next=0;
... ...
@@ -2368,6 +2436,54 @@ static struct socket_id* mk_listen_id(char* host, int proto, int port)
2368 2368
 }
2369 2369
 
2370 2370
 
2371
+static void free_name_lst(struct name_lst* lst)
2372
+{
2373
+	struct name_lst* tmp;
2374
+	
2375
+	while(lst){
2376
+		tmp=lst;
2377
+		lst=lst->next;
2378
+		pkg_free(tmp);
2379
+	}
2380
+}
2381
+
2382
+
2383
+static struct socket_id* mk_listen_id2(struct name_lst* addr_l, int proto,
2384
+										int port)
2385
+{
2386
+	struct socket_id* l;
2387
+	l=pkg_malloc(sizeof(struct socket_id));
2388
+	if (l==0) {
2389
+		LOG(L_CRIT,"ERROR: cfg. parser: out of memory.\n");
2390
+	} else {
2391
+		l->flags=addr_l->flags;
2392
+		l->port=port;
2393
+		l->proto=proto;
2394
+		l->addr_lst=addr_l;
2395
+		l->next=0;
2396
+	}
2397
+	return l;
2398
+}
2399
+
2400
+
2401
+static void free_socket_id(struct socket_id* i)
2402
+{
2403
+	free_name_lst(i->addr_lst);
2404
+	pkg_free(i);
2405
+}
2406
+
2407
+
2408
+static void free_socket_id_lst(struct socket_id* lst)
2409
+{
2410
+	struct socket_id* tmp;
2411
+	
2412
+	while(lst){
2413
+		tmp=lst;
2414
+		lst=lst->next;
2415
+		free_socket_id(tmp);
2416
+	}
2417
+}
2418
+
2371 2419
 /*
2372 2420
 int main(int argc, char ** argv)
2373 2421
 {
... ...
@@ -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 103
 	struct socket_info* prev;
104 104
 	unsigned short port_no;  /* port number */
105 105
 	char proto; /* tcp or udp*/
106
+	struct addr_info* addr_info_lst; /* extra addresses (e.g. SCTP mh) */
106 107
 };
107 108
 
108 109
 
... ...
@@ -135,8 +146,20 @@ struct dest_info{
135 135
 };
136 136
 
137 137
 
138
-struct socket_id{
138
+/* list of names for multi-homed sockets that need to bind on
139
+ * multiple addresses in the same time (sctp ) */
140
+struct name_lst{
139 141
 	char* name;
142
+	struct name_lst* next;
143
+	int flags;
144
+};
145
+
146
+
147
+struct socket_id{
148
+	struct name_lst* addr_lst; /* address list, the first one must
149
+								  be present and is the main one
150
+								  (in case of multihoming sctp)*/
151
+	int flags;
140 152
 	int proto;
141 153
 	int port;
142 154
 	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 506
 				if (cmd && cmd->fixup) {
507 507
 					int i;
508 508
 					DBG("fixing %s()\n", cmd->name);
509
-					/* type cast NUMBER to STRING, old modules may expect all STRING params during fixup */
509
+					/* type cast NUMBER to STRING, old modules may expect
510
+					 * all STRING params during fixup */
510 511
 					for (i=0; i<t->val[1].u.number; i++) {
511 512
 						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 */
513
+							snprintf(buf, sizeof(buf)-1, "%ld", 
514
+										t->val[i+2].u.number);
515
+							/* fixup currently requires string pkg_malloced*/
515 516
 							t->val[i+2].u.string = pkg_malloc(strlen(buf)+1);
516 517
 							if (!t->val[i+2].u.string) {
517
-								LOG(L_CRIT, "ERROR: cannot translate NUMBER to STRING\n");
518
+								LOG(L_CRIT, "ERROR: cannot translate NUMBER"
519
+											" to STRING\n");
518 520
 								return E_OUT_OF_MEM;
519 521
 							}
520 522
 							strcpy(t->val[i+2].u.string, buf);
... ...
@@ -539,11 +542,13 @@ static int fix_actions(struct action* a)
539 539
 								t->val[0].type);
540 540
 					return E_BUG;
541 541
 				}
542
-				he=resolvehost(((struct socket_id*)t->val[0].u.data)->name);
542
+				he=resolvehost(
543
+						((struct socket_id*)t->val[0].u.data)->addr_lst->name
544
+						);
543 545
 				if (he==0){
544 546
 					LOG(L_ERR, "ERROR: fix_actions: force_send_socket:"
545 547
 								" could not resolve %s\n",
546
-							((struct socket_id*)t->val[0].u.data)->name);
548
+						((struct socket_id*)t->val[0].u.data)->addr_lst->name);
547 549
 					return E_BAD_ADDRESS;
548 550
 				}
549 551
 				hostent2ip_addr(&ip, he, 0);
... ...
@@ -552,7 +557,7 @@ static int fix_actions(struct action* a)
552 552
 				if (si==0){
553 553
 					LOG(L_ERR, "ERROR: fix_actions: bad force_send_socket"
554 554
 							" argument: %s:%d (ser doesn't listen on it)\n",
555
-							((struct socket_id*)t->val[0].u.data)->name,
555
+						((struct socket_id*)t->val[0].u.data)->addr_lst->name,
556 556
 							((struct socket_id*)t->val[0].u.data)->port);
557 557
 					return E_BAD_ADDRESS;
558 558
 				}
... ...
@@ -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 103
 	}while(0)
104 104
 
105 105
 
106
+#define addr_info_listadd sock_listadd
107
+#define addr_info_listins sock_listins
108
+#define addr_info_listrm sock_listrm
109
+
110
+inline static void addr_info_list_ins_lst(struct addr_info* lst,
111
+										struct addr_info* after)
112
+{
113
+	struct addr_info* l;
114
+	struct addr_info* n;
115
+	
116
+	if (lst){
117
+		n=after->next;
118
+		after->next=lst;
119
+		lst->prev=after;
120
+		if (n){
121
+			for(l=lst; l->next; l=l->next);
122
+			l->next=n;
123
+			n->prev=l;
124
+		}
125
+	}
126
+}
127
+
106 128
 
107 129
 /* protocol order, filled by init_proto_order() */
108 130
 enum sip_protos nxt_proto[PROTO_LAST+1]=
... ...
@@ -110,12 +133,102 @@ enum sip_protos nxt_proto[PROTO_LAST+1]=
110 110
 
111 111
 
112 112
 
113
+/* another helper function, it just fills a struct addr_info
114
+ * returns: 0 on success, -1 on error*/
115
+static int init_addr_info(struct addr_info* a,
116
+								char* name, enum si_flags flags)
117
+{
118
+
119
+	memset(a, 0, sizeof(*a));
120
+	a->name.len=strlen(name);
121
+	a->name.s=pkg_malloc(a->name.len+1); /* include \0 */
122
+	if (a->name.s==0) goto error;
123
+	memcpy(a->name.s, name, a->name.len+1);
124
+	a->flags=flags;
125
+	return 0;
126
+error:
127
+	LOG(L_ERR, "ERROR: init_addr_info: memory allocation error\n");
128
+	return -1;
129
+}
130
+
131
+
132
+
133
+/* returns 0 on error, new addr_info_lst element on success */
134
+static inline struct addr_info* new_addr_info(char* name, 
135
+													enum si_flags gf)
136
+{
137
+	struct addr_info* al;
138
+	
139
+	al=pkg_malloc(sizeof(*al));
140
+	if (al==0) goto error;
141
+	al->next=0;
142
+	al->prev=0;
143
+	if (init_addr_info(al, name, gf)!=0) goto error;
144
+	return al;
145
+error:
146
+	LOG(L_ERR, "ERROR: new_addr_info: memory allocation error\n");
147
+	if (al){
148
+		if (al->name.s) pkg_free(al->name.s);
149
+		pkg_free(al);
150
+	}
151
+	return 0;
152
+}
153
+
154
+
155
+
156
+static inline void free_addr_info(struct addr_info* a)
157
+{
158
+	if (a){
159
+		if (a->name.s){
160
+			pkg_free(a->name.s);
161
+			a->name.s=0;
162
+		}
163
+		pkg_free(a);
164
+	}
165
+}
166
+
167
+
168
+
169
+static inline void free_addr_info_lst(struct addr_info** lst)
170
+{
171
+	struct addr_info* a;
172
+	struct addr_info* tmp;
173
+	
174
+	a=*lst;
175
+	while(a){
176
+		tmp=a;
177
+		a=a->next;
178
+		free_addr_info(tmp);
179
+	}
180
+}
181
+
182
+
183
+
184
+/* adds a new add_info_lst element to the corresponding list
185
+ * returns 0 on success, -1 on error */
186
+static int new_addr_info2list(char* name, enum si_flags f,
187
+								struct addr_info** l)
188
+{
189
+	struct addr_info * al;
190
+	
191
+	al=new_addr_info(name, f);
192
+	if (al==0) goto error;
193
+	addr_info_listadd(l, al);
194
+	return 0;
195
+error:
196
+	return -1;
197
+}
198
+
199
+
200
+
113 201
 /* another helper function, it just creates a socket_info struct */
114 202
 static inline struct socket_info* new_sock_info(	char* name,
203
+								struct name_lst* addr_l,
115 204
 								unsigned short port, unsigned short proto,
116 205
 								enum si_flags flags)
117 206
 {
118 207
 	struct socket_info* si;
208
+	struct name_lst* n;
119 209
 	
120 210
 	si=(struct socket_info*) pkg_malloc(sizeof(struct socket_info));
121 211
 	if (si==0) goto error;
... ...
@@ -129,6 +242,13 @@ static inline struct socket_info* new_sock_info(	char* name,
129 129
 	si->port_no=port;
130 130
 	si->proto=proto;
131 131
 	si->flags=flags;
132
+	si->addr_info_lst=0;
133
+	for (n=addr_l; n; n=n->next){
134
+		if (new_addr_info2list(n->name, n->flags, &si->addr_info_lst)!=0){
135
+			LOG(L_ERR, "ERROR: new_sockk_info:new_addr_info2list failed\n");
136
+			goto error;
137
+		}
138
+	}
132 139
 	return si;
133 140
 error:
134 141
 	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 145
 		if(si->name.s) pkg_free(si->name.s);
146 146
 		if(si->address_str.s) pkg_free(si->address_str.s);
147 147
 		if(si->port_no_str.s) pkg_free(si->port_no_str.s);
148
+		if (si->addr_info_lst) free_addr_info_lst(&si->addr_info_lst);
148 149
 	}
149 150
 }
150 151
 
... ...
@@ -204,6 +325,50 @@ static struct socket_info** get_sock_info_list(unsigned short proto)
204 204
 }
205 205
 
206 206
 
207
+/* helper function for grep_sock_info
208
+ * params:
209
+ *  host - hostname to compare with
210
+ *  name - official name
211
+ *  addr_str - name's resolved ip address converted to string
212
+ *  ip_addr - name's ip address 
213
+ *  flags - set to SI_IS_IP if name contains an IP
214
+ *
215
+ * returns 0 if host matches, -1 if not */
216
+inline static int si_hname_cmp(str* host, str* name, str* addr_str, 
217
+								struct ip_addr* ip_addr, int flags)
218
+{
219
+#ifdef USE_IPV6
220
+	struct ip_addr* ip6;
221
+#endif
222
+	
223
+	if ( (host->len==name->len) && 
224
+		(strncasecmp(host->s, name->s, name->len)==0) /*slower*/)
225
+		/* comp. must be case insensitive, host names
226
+		 * can be written in mixed case, it will also match
227
+		 * ipv6 addresses if we are lucky*/
228
+		goto found;
229
+	/* check if host == ip address */
230
+#ifdef USE_IPV6
231
+	/* ipv6 case is uglier, host can be [3ffe::1] */
232
+	ip6=str2ip6(host);
233
+	if (ip6){
234
+		if (ip_addr_cmp(ip6, ip_addr))
235
+			goto found; /* match */
236
+		else
237
+			return -1; /* no match, but this is an ipv6 address
238
+						 so no point in trying ipv4 */
239
+	}
240
+#endif
241
+	/* ipv4 */
242
+	if ( (!(flags&SI_IS_IP)) && (host->len==addr_str->len) && 
243
+			(memcmp(host->s, addr_str->s, addr_str->len)==0) )
244
+		goto found;
245
+	return -1;
246
+found:
247
+	return 0;
248
+}
249
+
250
+
207 251
 /* checks if the proto: host:port is one of the address we listen on
208 252
  * and returns the corresponding socket_info structure.
209 253
  * if port==0, the  port number is ignored
... ...
@@ -215,21 +380,18 @@ static struct socket_info** get_sock_info_list(unsigned short proto)
215 215
 struct socket_info* grep_sock_info(str* host, unsigned short port,
216 216
 												unsigned short proto)
217 217
 {
218
-	char* hname;
219
-	int h_len;
218
+	str hname;
220 219
 	struct socket_info* si;
221 220
 	struct socket_info** list;
221
+	struct addr_info* ai;
222 222
 	unsigned short c_proto;
223
+	
224
+	hname=*host;
223 225
 #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]==']')){
226
+	if ((hname.len>2)&&((*hname.s)=='[')&&(hname.s[hname.len-1]==']')){
230 227
 		/* ipv6 reference, skip [] */
231
-		hname++;
232
-		h_len-=2;
228
+		hname.s++;
229
+		hname.len-=2;
233 230
 	}
234 231
 #endif
235 232
 	c_proto=proto?proto:PROTO_UDP;
... ...
@@ -248,9 +410,9 @@ struct socket_info* grep_sock_info(str* host, unsigned short port,
248 248
 		for (si=*list; si; si=si->next){
249 249
 			DBG("grep_sock_info - checking if host==us: %d==%d && "
250 250
 					" [%.*s] == [%.*s]\n", 
251
-						h_len,
251
+						hname.len,
252 252
 						si->name.len,
253
-						h_len, hname,
253
+						hname.len, hname.s,
254 254
 						si->name.len, si->name.s
255 255
 				);
256 256
 			if (port) {
... ...
@@ -260,32 +422,14 @@ struct socket_info* grep_sock_info(str* host, unsigned short port,
260 260
 					continue;
261 261
 				}
262 262
 			}
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
-				)
263
+			if (si_hname_cmp(&hname, &si->name, &si->address_str, 
264
+								&si->address, si->flags)==0)
288 265
 				goto found;
266
+			/* try among the extra addresses */
267
+			for (ai=si->addr_info_lst; ai; ai=ai->next)
268
+				if (si_hname_cmp(&hname, &ai->name, &ai->address_str, 
269
+									&ai->address, ai->flags)==0)
270
+					goto found;
289 271
 		}
290 272
 	}while( (proto==0) && (c_proto=next_proto(c_proto)) );
291 273
 not_found:
... ...
@@ -323,8 +467,8 @@ struct socket_info* grep_sock_info_by_port(unsigned short port,
323 323
 			goto not_found; /* false */
324 324
 		}
325 325
 		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);
326
+			DBG("grep_sock_info_by_port - checking if port %d matches"
327
+					" port %d\n", si->port_no, port);
328 328
 			if (si->port_no==port) {
329 329
 				goto found;
330 330
 			}
... ...
@@ -352,6 +496,7 @@ struct socket_info* find_si(struct ip_addr* ip, unsigned short port,
352 352
 {
353 353
 	struct socket_info* si;
354 354
 	struct socket_info** list;
355
+	struct addr_info* ai;
355 356
 	unsigned short c_proto;
356 357
 	
357 358
 	c_proto=proto?proto:PROTO_UDP;
... ...
@@ -375,6 +520,9 @@ struct socket_info* find_si(struct ip_addr* ip, unsigned short port,
375 375
 			}
376 376
 			if (ip_addr_cmp(ip, &si->address))
377 377
 				goto found;
378
+			for (ai=si->addr_info_lst; ai; ai=ai->next)
379
+				if (ip_addr_cmp(ip, &ai->address))
380
+					goto found;
378 381
 		}
379 382
 	}while( (proto==0) && (c_proto=next_proto(c_proto)) );
380 383
 not_found:
... ...
@@ -385,43 +533,72 @@ found:
385 385
 
386 386
 
387 387
 
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)
388
+/* append a new sock_info structure to the corresponding list
389
+ * return  new sock info on success, 0 on error */
390
+static struct socket_info* new_sock2list(char* name, struct name_lst* addr_l,
391
+									unsigned short port,
392
+									unsigned short proto, enum si_flags flags,
393
+									struct socket_info** list)
392 394
 {
393 395
 	struct socket_info* si;
394 396
 	
395
-	si=new_sock_info(name, port, proto, flags);
397
+	si=new_sock_info(name, addr_l, port, proto, flags);
396 398
 	if (si==0){
397
-		LOG(L_ERR, "ERROR: add_listen_iface: new_sock_info failed\n");
399
+		LOG(L_ERR, "ERROR: new_sock2list: new_sock_info failed\n");
398 400
 		goto error;
399 401
 	}
400 402
 	sock_listadd(list, si);
403
+	return si;
404
+error:
401 405
 	return 0;
406
+}
407
+
408
+
409
+
410
+/* adds a new sock_info structure immediately after "after"
411
+ * return  new sock info on success, 0 on error */
412
+static struct socket_info* new_sock2list_after(char* name,
413
+									struct name_lst* addr_l,
414
+									unsigned short port,
415
+									unsigned short proto, enum si_flags flags,
416
+									struct socket_info* after)
417
+{
418
+	struct socket_info* si;
419
+	
420
+	si=new_sock_info(name, addr_l, port, proto, flags);
421
+	if (si==0){
422
+		LOG(L_ERR, "ERROR: new_sock2list_after: new_sock_info failed\n");
423
+		goto error;
424
+	}
425
+	sock_listins(si, after);
426
+	return si;
402 427
 error:
403
-	return -1;
428
+	return 0;
404 429
 }
405 430
 
406 431
 
407 432
 
408 433
 /* adds a sock_info structure to the corresponding proto list
409 434
  * return  0 on success, -1 on error */
410
-int add_listen_iface(char* name, unsigned short port, unsigned short proto,
435
+int add_listen_iface(char* name, struct name_lst* addr_l,
436
+						unsigned short port, unsigned short proto,
411 437
 						enum si_flags flags)
412 438
 {
413 439
 	struct socket_info** list;
414 440
 	unsigned short c_proto;
441
+	struct name_lst* a_l;
442
+	unsigned short c_port;
415 443
 	
416 444
 	c_proto=(proto)?proto:PROTO_UDP;
417 445
 	do{
418 446
 		list=get_sock_info_list(c_proto);
419 447
 		if (list==0){
420
-			LOG(L_ERR, "ERROR: add_listen_iface: get_sock_info_list failed\n");
448
+			LOG(L_ERR, "ERROR: add_listen_iface: get_sock_info_list"
449
+						" failed\n");
421 450
 			goto error;
422 451
 		}
423 452
 		if (port==0){ /* use default port */
424
-			port=
453
+			c_port=
425 454
 #ifdef USE_TLS
426 455
 				((c_proto)==PROTO_TLS)?tls_port_no:
427 456
 #endif
... ...
@@ -429,13 +606,34 @@ int add_listen_iface(char* name, unsigned short port, unsigned short proto,
429 429
 		}
430 430
 #ifdef USE_TLS
431 431
 		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++;
432
+			/* -l  ip:port => on udp:ip:port; tcp:ip:port and tls:ip:port+1?*/
433
+			c_port=port+1;
434 434
 		}
435 435
 #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;
436
+		else{
437
+			c_port=port;
438
+		}
439
+		if (c_proto!=PROTO_SCTP){
440
+			if (new_sock2list(name, 0, c_port, c_proto,
441
+								flags & ~SI_IS_MHOMED, list)==0){
442
+				LOG(L_ERR, "ERROR: add_listen_iface: new_sock2list failed\n");
443
+				goto error;
444
+			}
445
+			/* add the other addresses in the list as separate sockets
446
+			 * since only SCTP can bind to multiple addresses */
447
+			for (a_l=addr_l; a_l; a_l=a_l->next){
448
+				if (new_sock2list(a_l->name, 0, c_port, 
449
+									c_proto, flags & ~SI_IS_MHOMED, list)==0){
450
+					LOG(L_ERR, "ERROR: add_listen_iface: new_sock2list"
451
+								" failed\n");
452
+					goto error;
453
+				}
454
+			}
455
+		}else{
456
+			if (new_sock2list(name, addr_l, c_port, c_proto, flags, list)==0){
457
+				LOG(L_ERR, "ERROR: add_listen_iface: new_sock2list failed\n");
458
+				goto error;
459
+			}
439 460
 		}
440 461
 	}while( (proto==0) && (c_proto=next_proto(c_proto)));
441 462
 	return 0;
... ...
@@ -452,7 +650,7 @@ error:
452 452
  */
453 453
 int add_interfaces(char* if_name, int family, unsigned short port,
454 454
 					unsigned short proto,
455
-					struct socket_info** list)
455
+					struct addr_info** ai_l)
456 456
 {
457 457
 	struct ifconf ifc;
458 458
 	struct ifreq ifr;
... ...
@@ -552,9 +750,10 @@ int add_interfaces(char* if_name, int family, unsigned short port,
552 552
 			/* check if loopback */
553 553
 			if (ifrcopy.ifr_flags & IFF_LOOPBACK) 
554 554
 				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");
555
+			/* save the info */
556
+			if (new_addr_info2list(tmp, flags, ai_l)!=0){
557
+				LOG(L_ERR, "ERROR: add_interfaces: "
558
+						"new_addr_info2list failed\n");
558 559
 				goto error;
559 560
 			}
560 561
 			ret=0;
... ...
@@ -578,30 +777,229 @@ error:
578 578
 
579 579
 
580 580
 
581
+/* internal helper function: resolve host names and add aliases
582
+ * name is a value result parameter: it should contain the hostname that
583
+ * will be used to fill all the other members, including name itself
584
+ * in some situation (name->s should be a 0 terminated pkg_malloc'ed string)
585
+ * return 0 on success and -1 on error */
586
+static int fix_hostname(str* name, struct ip_addr* address, str* address_str,
587
+						enum si_flags* flags, int* type_flags,
588
+						struct socket_info* s)
589
+{
590
+	struct hostent* he;
591
+	char* tmp;
592
+	char** h;
593
+	
594
+	/* get "official hostnames", all the aliases etc. */
595
+	he=resolvehost(name->s);
596
+	if (he==0){
597
+		LOG(L_ERR, "ERROR: fix_hostname: could not resolve %s\n", name->s);
598
+		goto error;
599
+	}
600
+	/* check if we got the official name */
601
+	if (strcasecmp(he->h_name, name->s)!=0){
602
+		if (add_alias(name->s, name->len, s->port_no, s->proto)<0){
603
+			LOG(L_ERR, "ERROR: fix_hostname: add_alias failed\n");
604
+		}
605
+		/* change the official name */
606
+		pkg_free(name->s);
607
+		name->s=(char*)pkg_malloc(strlen(he->h_name)+1);
608
+		if (name->s==0){
609
+			LOG(L_ERR,  "ERROR: fix_hostname: out of memory.\n");
610
+			goto error;
611
+		}
612
+		name->len=strlen(he->h_name);
613
+		strncpy(name->s, he->h_name, name->len+1);
614
+	}
615
+	/* add the aliases*/
616
+	for(h=he->h_aliases; h && *h; h++)
617
+		if (add_alias(*h, strlen(*h), s->port_no, s->proto)<0){
618
+				LOG(L_ERR, "ERROR: fix_hostname: add_alias failed\n");
619
+		}
620
+	hostent2ip_addr(address, he, 0); /*convert to ip_addr format*/
621
+	if (type_flags){
622
+		*type_flags|=(address->af==AF_INET)?SOCKET_T_IPV4:SOCKET_T_IPV6;
623
+	}
624
+	if ((tmp=ip_addr2a(address))==0) goto error;
625
+	address_str->s=pkg_malloc(strlen(tmp)+1);
626
+	if (address_str->s==0){
627
+		LOG(L_ERR, "ERROR: fix_hostname: out of memory.\n");
628
+		goto error;
629
+	}
630
+	strncpy(address_str->s, tmp, strlen(tmp)+1);
631
+	/* set is_ip (1 if name is an ip address, 0 otherwise) */
632
+	address_str->len=strlen(tmp);
633
+	if ((address_str->len==name->len) &&
634
+		(strncasecmp(address_str->s, name->s, address_str->len)==0)){
635
+		*flags|=SI_IS_IP;
636
+		/* do rev. DNS on it (for aliases)*/
637
+		he=rev_resolvehost(address);
638
+		if (he==0){
639
+			LOG(L_WARN, "WARNING: fix_hostname: could not rev. resolve %s\n",
640
+					name->s);
641
+		}else{
642
+			/* add the aliases*/
643
+			if (add_alias(he->h_name, strlen(he->h_name), s->port_no,
644
+							s->proto)<0){
645
+				LOG(L_ERR, "ERROR: fix_hostname: add_alias failed\n");
646
+			}
647
+			for(h=he->h_aliases; h && *h; h++)
648
+				if (add_alias(*h, strlen(*h), s->port_no, s->proto) < 0){
649
+					LOG(L_ERR, "ERROR: fix_hostname: add_alias failed\n");
650
+				}
651
+		}
652
+	}
653
+	
654
+#ifdef USE_MCAST
655
+	/* Check if it is an multicast address and
656
+	 * set the flag if so
657
+	 */
658
+	if (is_mcast(address)){
659
+		*flags |= SI_IS_MCAST;
660
+	}
661
+#endif /* USE_MCAST */
662
+	
663
+	/* check if INADDR_ANY */
664
+	if (ip_addr_any(address))
665
+		*flags|=SI_IS_ANY;
666
+	
667
+	return 0;
668
+error:
669
+	return -1;
670
+}
671
+
672
+
673
+
674
+/* append new elements to a socket_info list after "list"
675
+ * each element is created  from addr_info_lst + port, protocol and flags
676
+ * return 0 on succes, -1 on error
677
+ */
678
+static int addr_info_to_si_lst(struct addr_info* ai_lst, unsigned short port,
679
+								char proto, enum si_flags flags,
680
+								struct socket_info** list)
681
+{
682
+	struct addr_info* ail;
683
+	
684
+	for (ail=ai_lst; ail; ail=ail->next){
685
+		if(new_sock2list(ail->name.s, 0, port_no, proto, ail->flags | flags,
686
+							list)==0)
687
+			return -1;
688
+	}
689
+	return 0;
690
+}
691
+
692
+
693
+
694
+/* insert new elements to a socket_info list after "el", 
695
+ * each element is created from addr_info_lst + port, * protocol and flags
696
+ * return 0 on succes, -1 on error
697
+ */
698
+static int addr_info_to_si_lst_after(struct addr_info* ai_lst,
699
+										unsigned short port,
700
+										char proto, enum si_flags flags,
701
+										struct socket_info* el)
702
+{
703
+	struct addr_info* ail;
704
+	struct socket_info* new_si;
705
+	
706
+	for (ail=ai_lst; ail; ail=ail->next){
707
+		if((new_si=new_sock2list_after(ail->name.s, 0, port_no, proto,
708
+								ail->flags | flags, el))==0)
709
+			return -1;
710
+		el=new_si;
711
+	}
712
+	return 0;
713
+}
714
+
715
+
716
+
581 717
 /* fixes a socket list => resolve addresses, 
582 718
  * interface names, fills missing members, remove duplicates
583 719
  * fills type_flags if not null with SOCKET_T_IPV4 and/or SOCKET_T_IPV6*/
584 720
 static int fix_socket_list(struct socket_info **list, int* type_flags)
585 721
 {
586 722
 	struct socket_info* si;
723
+	struct socket_info* new_si;
587 724
 	struct socket_info* l;
588 725
 	struct socket_info* next;
726
+	struct socket_info* next_si;
727
+	struct socket_info* del_si;
728
+	struct socket_info* keep_si;
589 729
 	char* tmp;
590 730
 	int len;
591
-	struct hostent* he;
592
-	char** h;
593
-	
731
+	struct addr_info* ai_lst;
732
+	struct addr_info* ail;
733
+	struct addr_info* tmp_ail;
734
+	struct addr_info* tmp_ail_next;
735
+	struct addr_info* ail_next;
736
+
594 737
 	if (type_flags)
595 738
 		*type_flags=0;
596 739
 	/* try to change all the interface names into addresses
597 740
 	 *  --ugly hack */
598 741
 	for (si=*list;si;){
599 742
 		next=si->next;
743
+		ai_lst=0;
600 744
 		if (add_interfaces(si->name.s, AF_INET, si->port_no,
601
-							si->proto, list)!=-1){
745
+							si->proto, &ai_lst)!=-1){
746
+			if (si->flags & SI_IS_MHOMED){
747
+				if((new_si=new_sock2list_after(ai_lst->name.s, 0, si->port_no,
748
+											si->proto,
749
+											ai_lst->flags|si->flags, si))==0)
750
+					break;
751
+				ail=ai_lst;
752
+				ai_lst=ai_lst->next;
753
+				free_addr_info(ail); /* free the first elem. */
754
+				if (ai_lst){
755
+					ai_lst->prev=0;
756
+					/* find the end */
757
+					for (ail=ai_lst; ail->next; ail=ail->next);
758
+					/* add the mh list after the last position in ai_lst */
759
+					addr_info_list_ins_lst(si->addr_info_lst, ail);
760
+					new_si->addr_info_lst=ai_lst;
761
+					si->addr_info_lst=0; /* detached and moved to new_si */
762
+					ail=ail->next; /* ail== old si->addr_info_lst */
763
+				}else{
764
+					ail=si->addr_info_lst;
765
+					new_si->addr_info_lst=ail;
766
+					si->addr_info_lst=0; /* detached and moved to new_si */
767
+				}
768
+				
769
+			}else{
770
+				/* add all addr. as separate  interfaces */
771
+				if (addr_info_to_si_lst_after(ai_lst, si->port_no, si->proto,
772
+						 						si->flags, si)!=0)
773
+					goto error;
774
+				/* ai_lst not needed anymore */
775
+				free_addr_info_lst(&ai_lst);
776
+				ail=0;
777
+				new_si=0;
778
+			}
602 779
 			/* success => remove current entry (shift the entire array)*/
603 780
 			sock_listrm(list, si);
604 781
 			free_sock_info(si);
782
+		}else{
783
+			new_si=si;
784
+			ail=si->addr_info_lst;
785
+		}
786
+		
787
+		if (ail){
788
+			if (new_si && (new_si->flags & SI_IS_MHOMED)){
789
+				ai_lst=0;
790
+				for (; ail;){
791
+					ail_next=ail->next;
792
+					if (add_interfaces(ail->name.s, AF_INET, new_si->port_no,
793
+											new_si->proto, &ai_lst)!=-1){
794
+						/* add the resolved list after the current position */
795
+						addr_info_list_ins_lst(ai_lst, ail);
796
+						/* success, remove the current entity */
797
+						addr_info_listrm(&new_si->addr_info_lst, ail);
798
+						free_addr_info(ail);
799
+						ai_lst=0;
800
+					}
801
+					ail=ail_next;
802
+				}
803
+			}
605 804
 		}
606 805
 		si=next;
607 806
 	}
... ...
@@ -632,87 +1030,16 @@ static int fix_socket_list(struct socket_info **list, int* type_flags)
632 632
 		strncpy(si->port_no_str.s, tmp, len+1);
633 633
 		si->port_no_str.len=len;
634 634
 		
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);
635
+		if (fix_hostname(&si->name, &si->address, &si->address_str,
636
+						&si->flags, type_flags, si) !=0 )
640 637
 			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");
638
+		/* fix hostnames in mh addresses */
639
+		for (ail=si->addr_info_lst; ail; ail=ail->next){
640
+			if (fix_hostname(&ail->name, &ail->address, &ail->address_str,
641
+						&ail->flags, type_flags, si) !=0 )
653 642
 				goto error;
654
-			}
655
-			si->name.len=strlen(he->h_name);
656
-			strncpy(si->name.s, he->h_name, si->name.len+1);
657 643
 		}
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 644
 		
712
-		/* check if INADDR_ANY */
713
-		if (ip_addr_any(&si->address))
714
-			si->flags|=SI_IS_ANY;
715
-
716 645
 #ifdef EXTRA_DEBUG
717 646
 		printf("              %.*s [%s]:%s%s\n", si->name.len, 
718 647
 				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 720
 #endif
721 721
 	}
722 722
 	/* removing duplicate addresses*/
723
-	for (si=*list;si; si=si->next){
723
+	for (si=*list;si; ){
724
+		next_si=si->next;
724 725
 		for (l=si->next;l;){
725 726
 			next=l->next;
726 727
 			if ((si->port_no==l->port_no) &&
727 728
 				(si->address.af==l->address.af) &&
728
-				(memcmp(si->address.u.addr, l->address.u.addr, si->address.len)
729
-					== 0)
729
+				(memcmp(si->address.u.addr, l->address.u.addr,
730
+						si->address.len) == 0)
730 731
 				){
732
+				/* remove the socket with no  extra addresses.,
733
+				 * if both of them have extra addresses, remove one of them
734
+				 * and merge the extra addresses into the other */
735
+				if (l->addr_info_lst==0){
736
+					del_si=l;
737
+					keep_si=si;
738
+				}else if (si->addr_info_lst==0){
739
+					del_si=si;
740
+					keep_si=l;
741
+				}else{
742
+					/* move l->addr_info_lst to si->addr_info_lst */
743
+					/* find last elem */
744
+					for (ail=si->addr_info_lst; ail->next; ail=ail->next);
745
+					/* add the l list after the last position in si lst */
746
+					addr_info_list_ins_lst(l->addr_info_lst, ail);
747
+					l->addr_info_lst=0; /* detached */
748
+					del_si=l; /* l will be removed */
749
+					keep_si=l;
750
+				}
731 751
 #ifdef EXTRA_DEBUG
732 752
 				printf("removing duplicate %s [%s] ==  %s [%s]\n",
733
-						si->name.s, si->address_str.s,
734
-						 l->name.s, l->address_str.s);
753
+						keep_si->name.s, keep_si->address_str.s,
754
+						 del_si->name.s, del_si->address_str.s);
735 755
 #endif
736 756
 				/* 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))
757
+				if ((!(del_si->flags& SI_IS_IP)) && (
758
+						(del_si->name.len!=keep_si->name.len)||
759
+						(strncmp(del_si->name.s, keep_si->name.s,
760
+								 del_si->name.len)!=0))
740 761
 					)
741
-					add_alias(l->name.s, l->name.len, l->port_no, l->proto);
762
+					add_alias(del_si->name.s, del_si->name.len,
763
+								l->port_no, l->proto);
742 764
 						
743
-				/* remove l*/
744
-				sock_listrm(list, l);
745
-				free_sock_info(l);
765
+				/* remove del_si*/
766
+				sock_listrm(list, del_si);
767
+				free_sock_info(del_si);
746 768
 			}
747 769
 			l=next;
748 770
 		}
771
+		si=next_si;
772
+	}
773
+	/* check for duplicates in extra_addresses */
774
+	for (si=*list;si; si=si->next){
775
+		/* check  for & remove internal duplicates: */
776
+		for (ail=si->addr_info_lst; ail;){
777
+			ail_next=ail->next;
778
+			/* 1. check if the extra addresses contain a duplicate for the 
779
+			 * main  one */
780
+			if ((ail->address.af==si->address.af) &&
781
+				(memcmp(ail->address.u.addr, si->address.u.addr,
782
+							ail->address.len) == 0)){
783
+				/* add the name to the alias list*/
784
+				if ((!(ail->flags& SI_IS_IP)) && (
785
+					(ail->name.len!=si->name.len)||
786
+					(strncmp(ail->name.s, si->name.s, ail->name.len)!=0)))
787
+					add_alias(ail->name.s, ail->name.len, si->port_no,
788
+								si->proto);
789
+					/* remove ail*/
790
+				addr_info_listrm(&si->addr_info_lst, ail);
791
+				free_addr_info(ail);
792
+				ail=ail_next;
793
+				continue;
794
+			}
795
+			/* 2. check if the extra addresses contain a duplicates for 
796
+			 *  other addresses in the same list */
797
+			for (tmp_ail=ail->next; tmp_ail;){
798
+				tmp_ail_next=tmp_ail->next;
799
+				if ((ail->address.af==tmp_ail->address.af) &&
800
+					(memcmp(ail->address.u.addr, tmp_ail->address.u.addr,
801
+							ail->address.len) == 0)){
802
+					/* add the name to the alias list*/
803
+					if ((!(tmp_ail->flags& SI_IS_IP)) && (
804
+						(ail->name.len!=tmp_ail->name.len)||
805
+						(strncmp(ail->name.s, tmp_ail->name.s,
806
+										tmp_ail->name.len)!=0))
807
+						)
808
+						add_alias(tmp_ail->name.s, tmp_ail->name.len,
809
+									si->port_no, si->proto);
810
+						/* remove tmp_ail*/
811
+					addr_info_listrm(&si->addr_info_lst, tmp_ail);
812
+					free_addr_info(tmp_ail);
813
+				}
814
+				tmp_ail=tmp_ail_next;
815
+			}
816
+			ail=ail_next;
817
+		}
818
+		/* check for duplicates between extra addresses (e.g. sctp MH)
819
+		 * and other main addresses, on conflict remove the corresponding
820
+		 * extra addresses (another possible solution would be to join
821
+		 * the 2 si entries into one). */
822
+		for (ail=si->addr_info_lst; ail;){
823
+			ail_next=ail->next;
824
+			for (l=*list;l; l=l->next){
825
+				if (l==si) continue;
826
+				if (si->port_no==l->port_no){
827
+					if ((ail->address.af==l->address.af) &&
828
+						(memcmp(ail->address.u.addr, l->address.u.addr,
829
+										ail->address.len) == 0)){
830
+						/* add the name to the alias list*/
831
+						if ((!(ail->flags& SI_IS_IP)) && (
832
+							(ail->name.len!=l->name.len)||
833
+							(strncmp(ail->name.s, l->name.s, l->name.len)!=0))
834
+							)
835
+							add_alias(ail->name.s, ail->name.len,
836
+										l->port_no, l->proto);
837
+						/* remove ail*/
838
+						addr_info_listrm(&si->addr_info_lst, ail);
839
+						free_addr_info(ail);
840
+						break;
841
+					}
842
+					/* check for duplicates with other  extra addresses
843
+					 * lists */
844
+					for (tmp_ail=l->addr_info_lst; tmp_ail; ){
845
+						tmp_ail_next=tmp_ail->next;
846
+						if ((ail->address.af==tmp_ail->address.af) &&
847
+							(memcmp(ail->address.u.addr,
848
+									tmp_ail->address.u.addr,
849
+									ail->address.len) == 0)){
850
+							/* add the name to the alias list*/
851
+							if ((!(tmp_ail->flags& SI_IS_IP)) && (
852
+									(ail->name.len!=tmp_ail->name.len)||
853
+									(strncmp(ail->name.s, tmp_ail->name.s,
854
+											tmp_ail->name.len)!=0))
855
+								)
856
+								add_alias(tmp_ail->name.s, tmp_ail->name.len,
857
+										l->port_no, l->proto);
858
+							/* remove tmp_ail*/
859
+							addr_info_listrm(&l->addr_info_lst, tmp_ail);
860
+							free_addr_info(tmp_ail);
861
+						}
862
+						tmp_ail=tmp_ail_next;
863
+					}
864
+				}
865
+			}
866
+			ail=ail_next;
867
+		}
749 868
 	}
750 869
 
751 870
 #ifdef USE_MCAST
752 871
 	     /* Remove invalid multicast entries */
753 872
 	si=*list;
754 873
 	while(si){
755
-		if ((si->flags & SI_IS_MCAST) && 
756
-		    ((si->proto == PROTO_TCP)
874
+		if ((si->proto == PROTO_TCP)
757 875
 #ifdef USE_TLS
758 876
 		    || (si->proto == PROTO_TLS)
759 877
 #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);
878
+#ifdef USE_SCTP
879
+			|| (si->proto == PROTO_SCTP)
880
+#endif
881
+			){
882
+			if (si->flags & SI_IS_MCAST){
883
+				LOG(L_WARN, "WARNING: removing entry %s:%s [%s]:%s\n",
884
+					get_proto_name(si->proto), si->name.s, 
885
+					si->address_str.s, si->port_no_str.s);
886
+				l = si;
887
+				si=si->next;
888
+				sock_listrm(list, l);
889
+				free_sock_info(l);
890
+			}else{
891
+				ail=si->addr_info_lst;
892
+				while(ail){
893
+					if (ail->flags & SI_IS_MCAST){
894
+						LOG(L_WARN, "WARNING: removing mh entry %s:%s"
895
+								" [%s]:%s\n",
896
+								get_proto_name(si->proto), ail->name.s, 
897
+								ail->address_str.s, si->port_no_str.s);
898
+						tmp_ail=ail;
899
+						ail=ail->next;
900
+						addr_info_listrm(&si->addr_info_lst, tmp_ail);
901
+						free_addr_info(tmp_ail);
902
+					}else{
903
+						ail=ail->next;
904
+					}
905
+				}
906
+				si=si->next;
907
+			}
768 908
 		} else {
769 909
 			si=si->next;
770 910
 		}
... ...
@@ -784,6 +1251,9 @@ int fix_all_socket_lists()
784 784
 {
785 785
 	struct utsname myname;
786 786
 	int flags;
787
+	struct addr_info* ai_lst;
788
+	
789
+	ai_lst=0;
787 790
 	
788 791
 	if ((udp_listen==0)
789 792
 #ifdef USE_TCP
... ...
@@ -797,26 +1267,40 @@ int fix_all_socket_lists()
797 797
 #endif
798 798
 		){
799 799
 		/* get all listening ipv4 interfaces */
800
-		if (add_interfaces(0, AF_INET, 0,  PROTO_UDP, &udp_listen)==0){
800
+		if ((add_interfaces(0, AF_INET, 0,  PROTO_UDP, &ai_lst)==0) &&
801
+			(addr_info_to_si_lst(ai_lst, 0, PROTO_UDP, 0, &udp_listen)==0)){
802
+			free_addr_info_lst(&ai_lst);
803
+			ai_lst=0;
801 804
 			/* if ok, try to add the others too */
802 805
 #ifdef USE_TCP
803 806
 			if (!tcp_disable){
804
-				if (add_interfaces(0, AF_INET, 0,  PROTO_TCP, &tcp_listen)!=0)
807
+				if ((add_interfaces(0, AF_INET, 0,  PROTO_TCP, &ai_lst)!=0) ||
808
+					(addr_info_to_si_lst(ai_lst, 0, PROTO_TCP, 0,
809
+										 				&tcp_listen)!=0))
805 810
 					goto error;
811
+				free_addr_info_lst(&ai_lst);
812
+				ai_lst=0;
806 813
 #ifdef USE_TLS
807 814
 				if (!tls_disable){
808
-					if (add_interfaces(0, AF_INET, 0, PROTO_TLS,
809
-								&tls_listen)!=0)
810
-					goto error;
815
+					if ((add_interfaces(0, AF_INET, 0, PROTO_TLS,
816
+										&ai_lst)!=0) ||
817
+						(addr_info_to_si_lst(ai_lst, 0, PROTO_TLS, 0,
818
+										 				&tls_listen)!=0))
819
+						goto error;
811 820
 				}
821
+				free_addr_info_lst(&ai_lst);
822
+				ai_lst=0;
812 823
 #endif
813 824
 			}
814 825
 #endif
815