81c5dbe9e992980ff518d04c027b5e26cbf6513d
[olsrd.git] / src / cfgparser / olsrd_conf.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon(olsrd)
3  * Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright 
11  *   notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright 
13  *   notice, this list of conditions and the following disclaimer in 
14  *   the documentation and/or other materials provided with the 
15  *   distribution.
16  * * Neither the name of olsr.org, olsrd nor the names of its 
17  *   contributors may be used to endorse or promote products derived 
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Visit http://www.olsr.org for more information.
34  *
35  * If you find this software useful feel free to make a donation
36  * to the project. For more information see the website or contact
37  * the copyright holders.
38  *
39  * $Id: olsrd_conf.c,v 1.57 2007/10/24 13:46:36 bernd67 Exp $
40  */
41
42
43 #include <stdio.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <stdlib.h>
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51
52 #include "olsrd_conf.h"
53 #include "olsr_cfg.h"
54
55
56 extern FILE *yyin;
57 extern int yyparse(void);
58
59 static char copyright_string[] __attribute__((unused)) = "The olsr.org Optimized Link-State Routing daemon(olsrd) Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org) All rights reserved.";
60
61 #ifdef MAKEBIN
62
63 /* Build as standalone binary */
64 int 
65 main(int argc, char *argv[])
66 {
67   struct olsrd_config *cnf;
68
69   if(argc == 1)
70     {
71       fprintf(stderr, "Usage: olsrd_cfgparser [filename] -print\n\n");
72       exit(EXIT_FAILURE);
73     }
74
75   if((cnf = olsrd_parse_cnf(argv[1])) != NULL)
76     {
77       if((argc > 2) && (!strcmp(argv[2], "-print")))
78         {
79           olsrd_print_cnf(cnf);  
80           olsrd_write_cnf(cnf, "./out.conf");
81         }
82       else
83         printf("Use -print to view parsed values\n");
84       printf("Configfile parsed OK\n");
85     }
86   else
87     {
88       printf("Failed parsing \"%s\"\n", argv[1]);
89     }
90
91   return 0;
92 }
93
94 #else
95
96 /* Build as part of olsrd */
97
98
99 #endif
100
101 struct olsrd_config *
102 olsrd_parse_cnf(const char *filename)
103 {
104   struct olsr_if *in, *new_ifqueue;
105   int rc;
106
107   struct olsrd_config *cnf = malloc(sizeof(struct olsrd_config));
108   if (cnf == NULL) {
109     fprintf(stderr, "Out of memory %s\n", __func__);
110     return NULL;
111   }
112
113   set_default_cnf(cnf);
114
115   printf("Parsing file: \"%s\"\n", filename);
116
117   yyin = fopen(filename, "r");
118   if (yyin == NULL) {
119     fprintf(stderr, "Cannot open configuration file '%s': %s.\n",
120             filename, strerror(errno));
121     free(cnf);
122     return NULL;
123   }
124
125   current_line = 1;
126   rc = yyparse();
127   fclose(yyin);
128   if (rc != 0) {
129     olsrd_free_cnf(cnf);
130     return NULL;
131   }
132
133   /* Reverse the queue (added by user request) */
134   in = cnf->interfaces;
135   new_ifqueue = NULL;
136
137   while(in) {
138     struct olsr_if *in_tmp = in; 
139     in = in->next;
140
141     in_tmp->next = new_ifqueue;
142     new_ifqueue = in_tmp;
143   }
144
145   cnf->interfaces = new_ifqueue;
146
147   for (in = cnf->interfaces; in != NULL; in = in->next) {
148       /* set various stuff */
149       in->configured = OLSR_FALSE;
150       in->interf = NULL;
151       in->host_emul = OLSR_FALSE;
152   }
153   return cnf;
154 }
155
156
157 int
158 olsrd_sanity_check_cnf(struct olsrd_config *cnf)
159 {
160   struct olsr_if           *in = cnf->interfaces;
161   struct if_config_options *io;
162
163   /* Debug level */
164   if(cnf->debug_level < MIN_DEBUGLVL ||
165      cnf->debug_level > MAX_DEBUGLVL)
166     {
167       fprintf(stderr, "Debuglevel %d is not allowed\n", cnf->debug_level);
168       return -1;
169     }
170
171   /* IP version */
172   if(cnf->ip_version != AF_INET &&
173      cnf->ip_version != AF_INET6)
174     {
175       fprintf(stderr, "Ipversion %d not allowed!\n", cnf->ip_version);
176       return -1;
177     }
178
179   /* TOS */
180   if(//cnf->tos < MIN_TOS ||
181      cnf->tos > MAX_TOS)
182     {
183       fprintf(stderr, "TOS %d is not allowed\n", cnf->tos);
184       return -1;
185     }
186
187   if(cnf->willingness_auto == OLSR_FALSE &&
188      (cnf->willingness > MAX_WILLINGNESS))
189     {
190       fprintf(stderr, "Willingness %d is not allowed\n", cnf->willingness);
191       return -1;
192     }
193
194   /* Hysteresis */
195   if(cnf->use_hysteresis == OLSR_TRUE)
196     {
197       if(cnf->hysteresis_param.scaling < MIN_HYST_PARAM ||
198          cnf->hysteresis_param.scaling > MAX_HYST_PARAM)
199         {
200           fprintf(stderr, "Hyst scaling %0.2f is not allowed\n", cnf->hysteresis_param.scaling);
201           return -1;
202         }
203
204       if(cnf->hysteresis_param.thr_high <= cnf->hysteresis_param.thr_low)
205         {
206           fprintf(stderr, "Hyst upper(%0.2f) thr must be bigger than lower(%0.2f) threshold!\n", cnf->hysteresis_param.thr_high, cnf->hysteresis_param.thr_low);
207           return -1;
208         }
209
210       if(cnf->hysteresis_param.thr_high < MIN_HYST_PARAM ||
211          cnf->hysteresis_param.thr_high > MAX_HYST_PARAM)
212         {
213           fprintf(stderr, "Hyst upper thr %0.2f is not allowed\n", cnf->hysteresis_param.thr_high);
214           return -1;
215         }
216
217       if(cnf->hysteresis_param.thr_low < MIN_HYST_PARAM ||
218          cnf->hysteresis_param.thr_low > MAX_HYST_PARAM)
219         {
220           fprintf(stderr, "Hyst lower thr %0.2f is not allowed\n", cnf->hysteresis_param.thr_low);
221           return -1;
222         }
223     }
224
225   /* Pollrate */
226
227   if(cnf->pollrate < MIN_POLLRATE ||
228      cnf->pollrate > MAX_POLLRATE)
229     {
230       fprintf(stderr, "Pollrate %0.2f is not allowed\n", cnf->pollrate);
231       return -1;
232     }
233
234   /* NIC Changes Pollrate */
235
236   if(cnf->nic_chgs_pollrate < MIN_NICCHGPOLLRT ||
237      cnf->nic_chgs_pollrate > MAX_NICCHGPOLLRT)
238     {
239       fprintf(stderr, "NIC Changes Pollrate %0.2f is not allowed\n", cnf->nic_chgs_pollrate);
240       return -1;
241     }
242
243   /* TC redundancy */
244
245   if(//cnf->tc_redundancy < MIN_TC_REDUNDANCY ||
246      cnf->tc_redundancy > MAX_TC_REDUNDANCY)
247     {
248       fprintf(stderr, "TC redundancy %d is not allowed\n", cnf->tc_redundancy);
249       return -1;
250     }
251
252   /* MPR coverage */
253   if(cnf->mpr_coverage < MIN_MPR_COVERAGE ||
254      cnf->mpr_coverage > MAX_MPR_COVERAGE)
255     {
256       fprintf(stderr, "MPR coverage %d is not allowed\n", cnf->mpr_coverage);
257       return -1;
258     }
259
260   /* Link Q and hysteresis cannot be activated at the same time */
261   if(cnf->use_hysteresis == OLSR_TRUE && cnf->lq_level)
262     {
263       fprintf(stderr, "Hysteresis and LinkQuality cannot both be active! Deactivate one of them.\n");
264       return -1;
265     }
266
267   /* Link quality level */
268
269   if(cnf->lq_level > MAX_LQ_LEVEL)
270     {
271       fprintf(stderr, "LQ level %d is not allowed\n", cnf->lq_level);
272       return -1;
273     }
274
275   /* Link quality window size */
276   if(cnf->lq_level && (cnf->lq_wsize < MIN_LQ_WSIZE || cnf->lq_wsize > MAX_LQ_WSIZE))
277     {
278       fprintf(stderr, "LQ window size %d is not allowed\n", cnf->lq_wsize);
279       return -1;
280     }
281
282   if(in == NULL)
283     {
284       fprintf(stderr, "No interfaces configured!\n");
285       return -1;
286     }
287
288   /* Interfaces */
289   while(in)
290     {
291       io = in->cnf;
292
293       if(in->name == NULL || !strlen(in->name))
294         {
295           fprintf(stderr, "Interface has no name!\n");
296           return -1;
297         }
298
299       if(io == NULL)
300         {
301           fprintf(stderr, "Interface %s has no configuration!\n", in->name);
302           return -1;
303         }
304         
305       /* HELLO interval */
306
307       if (io->hello_params.validity_time < 0.0)
308       {
309         if (cnf->lq_level == 0)
310           io->hello_params.validity_time = NEIGHB_HOLD_TIME;
311
312         else
313           io->hello_params.validity_time = cnf->lq_wsize * io->hello_params.emission_interval;
314       }
315
316       if(io->hello_params.emission_interval < cnf->pollrate ||
317          io->hello_params.emission_interval > io->hello_params.validity_time)
318         {
319           fprintf(stderr, "Bad HELLO parameters! (em: %0.2f, vt: %0.2f)\n", io->hello_params.emission_interval, io->hello_params.validity_time);
320           return -1;
321         }
322
323       /* TC interval */
324       if(io->tc_params.emission_interval < cnf->pollrate ||
325          io->tc_params.emission_interval > io->tc_params.validity_time)
326         {
327           fprintf(stderr, "Bad TC parameters! (em: %0.2f, vt: %0.2f)\n", io->tc_params.emission_interval, io->tc_params.validity_time);
328           return -1;
329         }
330
331       /* MID interval */
332       if(io->mid_params.emission_interval < cnf->pollrate ||
333          io->mid_params.emission_interval > io->mid_params.validity_time)
334         {
335           fprintf(stderr, "Bad MID parameters! (em: %0.2f, vt: %0.2f)\n", io->mid_params.emission_interval, io->mid_params.validity_time);
336           return -1;
337         }
338
339       /* HNA interval */
340       if(io->hna_params.emission_interval < cnf->pollrate ||
341          io->hna_params.emission_interval > io->hna_params.validity_time)
342         {
343           fprintf(stderr, "Bad HNA parameters! (em: %0.2f, vt: %0.2f)\n", io->hna_params.emission_interval, io->hna_params.validity_time);
344           return -1;
345         }
346
347       in = in->next;
348     }
349
350   return 0;
351 }
352
353
354 void
355 olsrd_free_cnf(struct olsrd_config *cnf)
356 {
357   struct hna4_entry        *h4d, *h4 = cnf->hna4_entries;
358   struct hna6_entry        *h6d, *h6 = cnf->hna6_entries;
359   struct olsr_if           *ind, *in = cnf->interfaces;
360   struct plugin_entry      *ped, *pe = cnf->plugins;
361   struct olsr_lq_mult      *mult, *next_mult;
362   
363   while(h4)
364     {
365       h4d = h4;
366       h4 = h4->next;
367       free(h4d);
368     }
369
370   while(h6)
371     {
372       h6d = h6;
373       h6 = h6->next;
374       free(h6d);
375     }
376
377   while(in)
378     {
379       for (mult = in->cnf->lq_mult; mult != NULL; mult = next_mult)
380       {
381         next_mult = mult->next;
382         free(mult);
383       }
384
385       free(in->cnf);
386       ind = in;
387       in = in->next;
388       free(ind->name);
389       free(ind->config);
390       free(ind);
391     }
392
393   while(pe)
394     {
395       ped = pe;
396       pe = pe->next;
397       free(ped->name);
398       free(ped);
399     }
400
401   return;
402 }
403
404
405
406 struct olsrd_config *
407 olsrd_get_default_cnf(void)
408 {
409   cnf = malloc(sizeof(struct olsrd_config));
410   if (cnf == NULL)
411     {
412       fprintf(stderr, "Out of memory %s\n", __func__);
413       return NULL;
414     }
415
416   set_default_cnf(cnf);
417
418   return cnf;
419 }
420
421
422
423
424 void
425 set_default_cnf(struct olsrd_config *cnf)
426 {
427     memset(cnf, 0, sizeof(struct olsrd_config));
428     
429     cnf->debug_level = DEF_DEBUGLVL;
430     cnf->no_fork = OLSR_FALSE;
431     cnf->host_emul = OLSR_FALSE;
432     cnf->ip_version  = AF_INET;
433     cnf->allow_no_interfaces = DEF_ALLOW_NO_INTS;
434     cnf->tos = DEF_TOS;
435     cnf->rttable = 254;
436     cnf->willingness_auto = DEF_WILL_AUTO;
437     cnf->ipc_connections = DEF_IPC_CONNECTIONS;
438     cnf->open_ipc = cnf->ipc_connections ? OLSR_TRUE : OLSR_FALSE;
439
440     cnf->use_hysteresis = DEF_USE_HYST;
441     cnf->hysteresis_param.scaling = HYST_SCALING;
442     cnf->hysteresis_param.thr_high = HYST_THRESHOLD_HIGH;
443     cnf->hysteresis_param.thr_low = HYST_THRESHOLD_LOW;
444
445     cnf->pollrate = DEF_POLLRATE;
446     cnf->nic_chgs_pollrate = DEF_NICCHGPOLLRT;
447
448     cnf->tc_redundancy = TC_REDUNDANCY;
449     cnf->mpr_coverage = MPR_COVERAGE;
450     cnf->lq_level = DEF_LQ_LEVEL;
451     cnf->lq_fish = DEF_LQ_FISH;
452     cnf->lq_dlimit = DEF_LQ_DIJK_LIMIT;
453     cnf->lq_dinter = DEF_LQ_DIJK_INTER;
454     cnf->lq_wsize = DEF_LQ_WSIZE;
455     cnf->clear_screen = DEF_CLEAR_SCREEN;
456
457     cnf->del_gws = OLSR_FALSE;
458     cnf->will_int = 10 * HELLO_INTERVAL;
459     cnf->max_jitter = 0.0;
460     cnf->exit_value = EXIT_SUCCESS;
461     cnf->max_tc_vtime = 0.0;
462     cnf->ioctl_s = 0;
463 #if LINUX_POLICY_ROUTING
464     cnf->rtnl_s = 0;
465 #else
466     cnf->rts = 0;
467 #endif
468 }
469
470
471
472
473 struct if_config_options *
474 get_default_if_config(void)
475 {
476   struct if_config_options *io = malloc(sizeof(struct if_config_options));
477   struct in6_addr in6;
478
479   if(io == NULL)
480     {
481       fprintf(stderr, "Out of memory %s\n", __func__);
482       return NULL;
483     }
484
485   memset(io, 0, sizeof(struct if_config_options));
486
487   io->ipv6_addrtype = 1; /* XXX - FixMe */
488
489   inet_pton(AF_INET6, OLSR_IPV6_MCAST_SITE_LOCAL, &in6);
490   memcpy(&io->ipv6_multi_site.v6, &in6, sizeof(struct in6_addr));
491
492   inet_pton(AF_INET6, OLSR_IPV6_MCAST_GLOBAL, &in6);
493   memcpy(&io->ipv6_multi_glbl.v6, &in6, sizeof(struct in6_addr));
494
495   io->lq_mult = NULL;
496
497   io->weight.fixed = OLSR_FALSE;
498   io->weight.value = 0;
499
500   io->ipv6_addrtype = 0; /* global */
501
502   io->hello_params.emission_interval = HELLO_INTERVAL;
503   io->hello_params.validity_time = -1.0;
504   io->tc_params.emission_interval = TC_INTERVAL;
505   io->tc_params.validity_time = TOP_HOLD_TIME;
506   io->mid_params.emission_interval = MID_INTERVAL;
507   io->mid_params.validity_time = MID_HOLD_TIME;
508   io->hna_params.emission_interval = HNA_INTERVAL;
509   io->hna_params.validity_time = HNA_HOLD_TIME;
510   io->autodetect_chg = OLSR_TRUE;
511
512   return io;
513
514 }
515
516
517
518 void
519 olsrd_print_cnf(struct olsrd_config *cnf)
520 {
521   struct hna4_entry        *h4 = cnf->hna4_entries;
522   struct hna6_entry        *h6 = cnf->hna6_entries;
523   struct olsr_if           *in = cnf->interfaces;
524   struct plugin_entry      *pe = cnf->plugins;
525   struct ipc_host          *ih = cnf->ipc_hosts;
526   struct ipc_net           *ie = cnf->ipc_nets;
527   struct olsr_lq_mult      *mult;
528   char ipv6_buf[100];             /* buffer for IPv6 inet_htop */
529   struct in_addr in4;
530
531   printf(" *** olsrd configuration ***\n");
532
533   printf("Debug Level      : %d\n", cnf->debug_level);
534   if(cnf->ip_version == AF_INET6)
535     printf("IpVersion        : 6\n");
536   else
537     printf("IpVersion        : 4\n");
538   if(cnf->allow_no_interfaces)
539     printf("No interfaces    : ALLOWED\n");
540   else
541     printf("No interfaces    : NOT ALLOWED\n");
542   printf("TOS              : 0x%02x\n", cnf->tos);
543   printf("RtTable          : 0x%02x\n", cnf->rttable);
544   if(cnf->willingness_auto)
545     printf("Willingness      : AUTO\n");
546   else
547     printf("Willingness      : %d\n", cnf->willingness);
548
549   printf("IPC connections  : %d\n", cnf->ipc_connections);
550
551   while(ih)
552     {
553       in4.s_addr = ih->host.v4;
554       printf("\tHost %s\n", inet_ntoa(in4));
555       ih = ih->next;
556     }
557   
558   while(ie)
559     {
560       in4.s_addr = ie->net.v4;
561       printf("\tNet %s/", inet_ntoa(in4));
562       in4.s_addr = ie->mask.v4;
563       printf("%s\n", inet_ntoa(in4));
564       ie = ie->next;
565     }
566
567
568   printf("Pollrate         : %0.2f\n", cnf->pollrate);
569
570   printf("NIC ChangPollrate: %0.2f\n", cnf->nic_chgs_pollrate);
571
572   printf("TC redundancy    : %d\n", cnf->tc_redundancy);
573
574   printf("MPR coverage     : %d\n", cnf->mpr_coverage);
575    
576   printf("LQ level         : %d\n", cnf->lq_level);
577
578   printf("LQ fish eye      : %d\n", cnf->lq_fish);
579
580   printf("LQ Dijkstra limit: %d, %0.2f\n", cnf->lq_dlimit, cnf->lq_dinter);
581
582   printf("LQ window size   : %d\n", cnf->lq_wsize);
583
584   printf("Clear screen     : %s\n", cnf->clear_screen ? "yes" : "no");
585
586   /* Interfaces */
587   if(in)
588     {
589       printf("Interfaces:\n");
590       while(in)
591         {
592           printf(" dev: \"%s\"\n", in->name);
593           
594           if(in->cnf->ipv4_broadcast.v4)
595             {
596               in4.s_addr = in->cnf->ipv4_broadcast.v4;
597               printf("\tIPv4 broadcast           : %s\n", inet_ntoa(in4));
598             }
599           else
600             {
601               printf("\tIPv4 broadcast           : AUTO\n");
602             }
603           
604           printf("\tIPv6 addrtype            : %s\n", in->cnf->ipv6_addrtype ? "site-local" : "global");
605           
606           //union olsr_ip_addr       ipv6_multi_site;
607           //union olsr_ip_addr       ipv6_multi_glbl;
608           printf("\tIPv6 multicast site/glbl : %s", (char *)inet_ntop(AF_INET6, &in->cnf->ipv6_multi_site.v6, ipv6_buf, sizeof(ipv6_buf)));
609           printf("/%s\n", (char *)inet_ntop(AF_INET6, &in->cnf->ipv6_multi_glbl.v6, ipv6_buf, sizeof(ipv6_buf)));
610           
611           printf("\tHELLO emission/validity  : %0.2f/%0.2f\n", in->cnf->hello_params.emission_interval, in->cnf->hello_params.validity_time);
612           printf("\tTC emission/validity     : %0.2f/%0.2f\n", in->cnf->tc_params.emission_interval, in->cnf->tc_params.validity_time);
613           printf("\tMID emission/validity    : %0.2f/%0.2f\n", in->cnf->mid_params.emission_interval, in->cnf->mid_params.validity_time);
614           printf("\tHNA emission/validity    : %0.2f/%0.2f\n", in->cnf->hna_params.emission_interval, in->cnf->hna_params.validity_time);
615           
616           for (mult = in->cnf->lq_mult; mult != NULL; mult = mult->next)
617           {
618             inet_ntop(cnf->ip_version, &mult->addr, ipv6_buf,
619                       sizeof (ipv6_buf));
620
621             printf("\tLinkQualityMult          : %s %0.2f\n",
622                    ipv6_buf, mult->val);
623           }
624
625           printf("\tAutodetetc changes       : %s\n", in->cnf->autodetect_chg ? "yes" : "no");
626
627           in = in->next;
628         }
629     }
630
631
632
633
634   /* Plugins */
635   if(pe)
636     {
637       printf("Plugins:\n");
638
639       while(pe)
640         {
641           printf("\tName: \"%s\"\n", pe->name);
642           pe = pe->next;
643         }
644     }
645
646   /* Hysteresis */
647   if(cnf->use_hysteresis)
648     {
649       printf("Using hysteresis:\n");
650       printf("\tScaling      : %0.2f\n", cnf->hysteresis_param.scaling);
651       printf("\tThr high/low : %0.2f/%0.2f\n", cnf->hysteresis_param.thr_high, cnf->hysteresis_param.thr_low);
652     }
653   else
654     printf("Not using hysteresis\n");
655
656   /* HNA IPv4 */
657   if(h4)
658     {
659
660       printf("HNA4 entries:\n");
661       while(h4)
662         {
663           in4.s_addr = h4->net.v4;
664           printf("\t%s/", inet_ntoa(in4));
665           in4.s_addr = h4->netmask.v4;
666           printf("%s\n", inet_ntoa(in4));
667
668           h4 = h4->next;
669         }
670     }
671
672   /* HNA IPv6 */
673   if(h6)
674     {
675       printf("HNA6 entries:\n");
676       while(h6)
677         {
678           printf("\t%s/%d\n", (char *)inet_ntop(AF_INET6, &h6->net.v6, ipv6_buf, sizeof(ipv6_buf)), h6->prefix_len);
679           h6 = h6->next;
680         }
681     }
682 }
683
684 #if defined WIN32_STDIO_HACK
685 struct ioinfo
686 {
687         unsigned int handle;
688         unsigned char attr;
689         char buff;
690         int flag;
691         CRITICAL_SECTION lock;
692 };
693
694 void win32_stdio_hack(unsigned int handle)
695 {
696   HMODULE lib;
697   struct ioinfo **info;
698
699   lib = LoadLibrary("msvcrt.dll");
700
701   info = (struct ioinfo **)GetProcAddress(lib, "__pioinfo");
702
703   // (*info)[1].handle = handle;
704   // (*info)[1].attr = 0x89; // FOPEN | FTEXT | FPIPE;
705
706   (*info)[2].handle = handle;
707   (*info)[2].attr = 0x89;
708
709   // stdout->_file = 1;
710   stderr->_file = 2;
711
712   // setbuf(stdout, NULL);
713   setbuf(stderr, NULL);
714 }
715 #endif