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