1 /*
2  *
3  * XASTIR, Amateur Station Tracking and Information Reporting
4  * Copyright (C) 1999,2000  Frank Giannandrea
5  * Copyright (C) 2000-2019 The Xastir Group
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * Look at the README for more information on the program.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25   #include "config.h"
26 #endif  // HAVE_CONFIG_H
27 
28 #include "snprintf.h"
29 
30 #include <Xm/XmAll.h>
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <netdb.h>
36 #include <signal.h>
37 
38 //Needed for Solaris 2.5
39 #include <netinet/in.h>
40 
41 #include <arpa/inet.h>
42 #include <sys/socket.h>
43 #include <setjmp.h>
44 #include <netinet/in.h>
45 #include <sys/wait.h>
46 #include <errno.h>
47 
48 #include "xastir.h"
49 #include "main.h"
50 #include "lang.h"
51 
52 // Must be last include file
53 #include "leak_detection.h"
54 #include "forked_getaddrinfo.h"
55 
56 #ifndef HAVE_SIGHANDLER_T
57   #ifdef HAVE_SIG_T
58     typedef sig_t sighandler_t;
59   #else
60     typedef void (*sighandler_t)(int);
61   #endif
62 #endif
63 
64 
65 #ifndef __LCLINT__
66   #ifndef HAVE_SIGJMP_BUF
67     jmp_buf ret_place;
68   #else // HAVE_SIGJMP_BUF
69     static  sigjmp_buf ret_place;       /* Jump address if alarm */
70   #endif    // HAVE_SIGJMP_BUF
71 #endif // __LCLINT__
72 
73 
74 
75 
76 
77 /*************************************************************************/
78 /* Time out on connect                                                   */
79 /* In case there is a problem in getting the hostname or connecting      */
80 /* (see  setjmp below).                                                  */
81 /*************************************************************************/
82 
host_time_out(int UNUSED (sig))83 static void host_time_out( int UNUSED(sig) )
84 {
85 #ifndef __LCLINT__
86   siglongjmp(ret_place,0);
87 #endif // __LCLINT__
88 }
89 
90 
91 
92 
93 
94 /*************************************************************************/
95 /* do a nice host lookup (don't thread!!)                                */
96 /*                                                                       */
97 /* host: name to lookup                                                  */
98 /* ip: buffer for ip's must be 400 bytes at least                        */
99 /* time: time in seconds to wait                                         */
100 /*                                                                       */
101 /* return the ip or ip's of the host name                                */
102 /* or these strings:                                                     */
103 /* NOHOST  for no host by that name found                                */
104 /* NOIP    for host found but no ip address available                    */
105 /* TIMEOUT for time exceeded                                             */
106 /*************************************************************************/
107 
forked_getaddrinfo(const char * hostname,const char * servname,const struct addrinfo * hints,struct addrinfo ** resout,int time)108 int forked_getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **resout, int time)
109 {
110 
111 #ifdef RETSIGTYPE
112   RETSIGTYPE * previous_loc;
113 #else
114 #error RETSIGTYPE not defined
115 #endif
116 
117   pid_t host_pid;
118   int status;
119   int fp[2];
120   int tm;
121   int i;
122   int rc = EAI_FAIL;
123   char ttemp[60];
124   int wait_host;
125   struct addrinfo *res0;
126   struct addrinfo *res;
127 
128   if (debug_level & 1024)
129   {
130     fprintf(stderr,"Start Host lookup\n");
131   }
132 
133   busy_cursor(appshell);
134 
135   if (debug_level & 1024)
136   {
137     fprintf(stderr,"Creating pipe\n");
138   }
139 
140   // Create a pipe for communication
141   if (pipe(fp)!=0)
142   {
143     fprintf(stderr, "Error creating pipe for hostname lookup: %s\n",
144             strerror(errno));
145     return rc;
146   }
147 
148   host_pid = fork();      // Fork off a child process
149 
150   if (debug_level & 1024)
151   {
152     fprintf(stderr,"Host fork\n");
153   }
154 
155   if (host_pid!=-1)       // If the fork was successful
156   {
157 
158 //---------------------------------------------------------------------------------------
159     if (host_pid==0)    // We're in the child process
160     {
161 
162 
163       // Go back to default signal handler instead of
164       // calling restart() on SIGHUP
165       (void) signal(SIGHUP,SIG_DFL);
166 
167 
168       // Change the name of the new child process.  So far
169       // this only works for "ps" listings, not for "top".
170       // This code only works on Linux.  For BSD use
171       // setproctitle(3), NetBSD can use setprogname(2).
172 #ifdef __linux__
173       init_set_proc_title(my_argc, my_argv, my_envp);
174       set_proc_title("%s", "hostname lookup (xastir)");
175       //fprintf(stderr,"DEBUG: %s\n", Argv[0]);
176 #endif  // __linux__
177 
178 
179       // Close the end of the pipe we don't need here
180 
181       if (debug_level & 1024)
182       {
183         fprintf(stderr,"Child closing read end of pipe\n");
184       }
185 
186       close(fp[0]);   // Read end of the pipe
187 
188       if (debug_level & 1024)
189       {
190         fprintf(stderr,"Set alarm \n");
191       }
192 
193 #ifdef RETSIGTYPE
194       previous_loc = (RETSIGTYPE *)signal(SIGALRM, host_time_out);
195 #else
196       previous_loc = signal(SIGALRM, host_time_out);
197 #endif
198 
199       // Set up to jump here if we time out on SIGALRM
200       if (sigsetjmp(ret_place,-1)!=0)
201       {
202 
203         // Turn off the alarm
204         (void)alarm(0);
205 
206         // Reset the SIGALRM handler to its previous value
207         (void)signal(SIGALRM, (sighandler_t)previous_loc);
208 
209         // Return net connection time out
210         rc = FAI_TIMEOUT;
211 
212         if (write(fp[1],&rc, sizeof(int)) == -1)
213         {
214           // Write error. Do nothing as we did prior
215           // to checking the return value.
216         }
217 
218         if (debug_level & 1024)
219         {
220           fprintf(stderr,"Child closing write end of pipe\n");
221         }
222 
223         close(fp[1]);   // All done writing to the pipe
224         exit(EXIT_FAILURE); // Exit from child process
225       }
226       (void)alarm(time);  // Start the timer
227 
228       // Make the call that may time out if no response from DNS
229       /*hostinfo = gethostbyname2(host,AF_INET); some systems don't have this*/
230       rc = getaddrinfo(hostname, servname, hints, &res0);
231 
232       // If we get to here, we haven't timed out
233       // and we have an answer to process.
234 
235       // Turn off the alarm
236       (void)alarm(0);
237       // Reset the SIGALRM handler to its previous value
238       (void)signal(SIGALRM, (sighandler_t)previous_loc);
239 
240       if (write(fp[1], &rc, sizeof(int)) == -1)    // Send status
241       {
242         // Write error. Do nothing as we did prior
243         // to checking the return value.
244       }
245 
246       for (res = res0; res; res = res->ai_next)
247       {
248         // Signal that an entry is coming.
249         rc = 1;
250 
251         if (write(fp[1], &rc, sizeof(int)) == -1)
252         {
253           // Write error. Do nothing as we did prior
254           // to checking the return value.
255         }
256 
257         // Send  entry
258         if (write(fp[1], res, sizeof(struct addrinfo)) == -1)
259         {
260           // Write error. Do nothing as we did prior
261           // to checking the return value.
262         }
263 
264         if (write(fp[1], res->ai_addr, res->ai_addrlen) == -1)
265         {
266           // Write error. Do nothing as we did prior
267           // to checking the return value.
268         }
269 
270       }
271       // Signal that there is nothing left
272       rc = 0;
273 
274       if (write(fp[1], &rc, sizeof(int)) == -1)
275       {
276         // Write error. Do nothing as we did prior
277         // to checking the return value.
278       }
279 
280       if (debug_level & 1024)
281       {
282         fprintf(stderr,"Child closing write end of pipe\n");
283       }
284 
285       freeaddrinfo(res0);
286       close(fp[1]);   // All done writing to the pipe
287       exit(EXIT_FAILURE); // Exit from child process
288 
289     }   // End of child process
290 //---------------------------------------------------------------------------------------
291     else
292     {
293       // We're in the parent process at this point
294 
295       // Close the end of the pipe we don't need here
296 
297       if (debug_level & 1024)
298       {
299         fprintf(stderr,"Parent closing write end of pipe\n");
300       }
301 
302       close(fp[1]);   // Write end of the pipe
303 
304       tm=1;
305       wait_host=1;
306       while (wait_host!=-1)
307       {
308         xastir_snprintf(ttemp, sizeof(ttemp), langcode("BBARSTA031"), tm++);
309         statusline(ttemp,1);        // Looking up hostname...
310 
311         for (i=0; i < 60 && wait_host!=-1; i++)
312         {
313           wait_host=waitpid(host_pid,&status,WNOHANG);
314           /* update display while waiting */
315 //                        XmUpdateDisplay(XtParent(da));
316           //usleep(500);
317           sched_yield();
318         }
319       }
320       // Get the return code
321       if (read(fp[0],&rc,sizeof(int)) == -1)
322       {
323         // Read error. Do nothing as we did prior
324         // to checking the return value.
325       }
326 
327       if(rc!=0)
328       {
329         close(fp[0]);
330         return rc;
331       }
332 
333       if (read(fp[0], &status, sizeof(int)) == -1)
334       {
335         // Read error. Do nothing as we did prior
336         // to checking the return value.
337       }
338 
339       while(status)
340       {
341         *resout = (struct addrinfo*) malloc(sizeof(struct addrinfo));
342         res = *resout;
343 
344         if (read(fp[0], res, sizeof(struct addrinfo)) == -1)
345         {
346           // Read error. Do nothing as we did prior
347           // to checking the return value.
348         }
349 
350         res->ai_addr = (struct sockaddr*) malloc(res->ai_addrlen);
351 
352         if (read(fp[0], res->ai_addr, res->ai_addrlen) == -1)
353         {
354           // Read error. Do nothing as we did prior
355           // to checking the return value.
356         }
357 
358         res->ai_canonname = NULL;
359         resout = &res->ai_next;
360 
361         // See if there is another
362         if (read(fp[0], &status, sizeof(int)) == -1)
363         {
364           // Read error. Do nothing as we did prior
365           // to checking the return value.
366         }
367       }
368       *resout = NULL;
369 
370       if (debug_level & 1024)
371       {
372         fprintf(stderr,"Parent closing read end of pipe\n");
373       }
374 
375       close(fp[0]);   // Close the read end of the pipe
376     }
377   }
378   else    // We didn't fork
379   {
380     // Close both ends of the pipe to make
381     // sure we've cleaned up properly
382     close(fp[0]);
383     close(fp[1]);
384   }
385   return rc;
386 }
387 
forked_freeaddrinfo(struct addrinfo * ai)388 void forked_freeaddrinfo(struct addrinfo *ai)
389 {
390   struct addrinfo *next = ai;
391   struct addrinfo *current = ai;
392 
393   while(next)
394   {
395     current = next;
396     next = current->ai_next;
397 
398     free(current->ai_addr);
399     free(current);
400   }
401 }
402 
403 
404