1 /** @file
2 
3   Some utility and support functions for the management module.
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 #include "tscore/ink_platform.h"
24 #include "tscore/ink_sock.h"
25 #include "MgmtUtils.h"
26 #include "MgmtSocket.h"
27 #include "tscore/Diags.h"
28 
29 #include "LocalManager.h"
30 
31 static int use_syslog = 0;
32 
33 /* mgmt_use_syslog()
34  *
35  *    Called to indicate that the syslog should be used and
36  *       the log has been opened
37  */
38 void
mgmt_use_syslog()39 mgmt_use_syslog()
40 {
41   use_syslog = 1;
42 }
43 
44 /*
45  * mgmt_readline(...)
46  *   Simple, inefficient, read line function. Takes a socket to read
47  * from, a char * to write into, and a max len to read. The newline
48  * is stripped.
49  *
50  * Returns:  num bytes read
51  *           -1  error
52  */
53 int
mgmt_readline(int soc,char * buf,int maxlen)54 mgmt_readline(int soc, char *buf, int maxlen)
55 {
56   int n = 0;
57   char c;
58 
59   for (; n < maxlen; n++) {
60     int rc = read_socket(soc, &c, 1);
61     if (rc == 1) {
62       *buf++ = c;
63       if (c == '\n') {
64         --buf;
65         *buf = '\0';
66         if (*(buf - 1) == '\r') {
67           --buf;
68           *buf = '\0';
69         }
70         break;
71       }
72     } else if (rc == 0) {
73       return n;
74     } else { /* Error */
75       if (errno == ECONNRESET || errno == EPIPE) {
76         return n ? n : 0;
77       }
78 
79       if (mgmt_transient_error()) {
80         mgmt_sleep_msec(1);
81         continue;
82       }
83 
84       return -1;
85     }
86   }
87 
88   return n;
89 } /* End mgmt_readline */
90 
91 /*
92  * mgmt_writeline(...)
93  *   Simple, inefficient, write line function. Takes a soc to write to,
94  * a char * containing the data, and the number of bytes to write.
95  * It sends nbytes + 1 bytes worth of data, the + 1 being the newline
96  * character.
97  *
98  * Returns:    num bytes not written
99  *             -1  error
100  */
101 int
mgmt_writeline(int soc,const char * data,int nbytes)102 mgmt_writeline(int soc, const char *data, int nbytes)
103 {
104   int nleft, n = 0;
105   const char *tmp = data;
106 
107   nleft = nbytes;
108   while (nleft > 0) {
109     int nwritten = write_socket(soc, tmp, nleft);
110     if (nwritten == 0) { // Nothing written
111       mgmt_sleep_msec(1);
112       continue;
113     } else if (nwritten < 0) { // Error
114       if (mgmt_transient_error()) {
115         mgmt_sleep_msec(1);
116         continue;
117       }
118 
119       return nwritten;
120     }
121     nleft -= nwritten;
122     tmp += nwritten;
123   }
124 
125   while (n != 1) {
126     n = write_socket(soc, "\n", 1); /* Terminating newline */
127     if (n == 0) {
128       mgmt_sleep_msec(1);
129       continue;
130     } else if (n < 0) { // Error
131       if (mgmt_transient_error()) {
132         mgmt_sleep_msec(1);
133         continue;
134       }
135 
136       return n;
137     }
138   }
139 
140   return (nleft); /* Paranoia */
141 } /* End mgmt_writeline */
142 
143 /*
144  * mgmt_read_pipe()
145  * - Reads from a pipe
146  *
147  * Returns: bytes read
148  *          0 on EOF
149  *          -errno on error
150  */
151 
152 int
mgmt_read_pipe(int fd,char * buf,int bytes_to_read)153 mgmt_read_pipe(int fd, char *buf, int bytes_to_read)
154 {
155   char *p        = buf;
156   int bytes_read = 0;
157 
158   while (bytes_to_read > 0) {
159     int err = read_socket(fd, p, bytes_to_read);
160     if (err == 0) {
161       // return 0 if partial read.
162       return err;
163     } else if (err < 0) {
164       // Turn ECONNRESET into EOF.
165       if (errno == ECONNRESET || errno == EPIPE) {
166         return bytes_read ? bytes_read : 0;
167       }
168 
169       if (mgmt_transient_error()) {
170         mgmt_sleep_msec(1);
171         continue;
172       }
173 
174       return -errno;
175     }
176 
177     bytes_to_read -= err;
178     bytes_read += err;
179     p += err;
180   }
181 
182   return bytes_read;
183 }
184 
185 /*
186  * mgmt_write_pipe()
187  * - Writes to a pipe
188  *
189  * Returns: bytes written
190  *          0 on EOF
191  *          -errno on error
192  */
193 
194 int
mgmt_write_pipe(int fd,char * buf,int bytes_to_write)195 mgmt_write_pipe(int fd, char *buf, int bytes_to_write)
196 {
197   char *p           = buf;
198   int bytes_written = 0;
199 
200   while (bytes_to_write > 0) {
201     int err = write_socket(fd, p, bytes_to_write);
202     if (err == 0) {
203       // Where this volume of IEEE Std 1003.1-2001 requires -1 to be returned and errno set to [EAGAIN],
204       // most historical implementations return zero for write(2)
205       mgmt_sleep_msec(1);
206       continue;
207     } else if (err < 0) {
208       if (mgmt_transient_error()) {
209         mgmt_sleep_msec(1);
210         continue;
211       }
212 
213       return -errno;
214     }
215 
216     bytes_to_write -= err;
217     bytes_written += err;
218     p += err;
219   }
220 
221   return bytes_written;
222 }
223 
224 void
mgmt_log(const char * message_format,...)225 mgmt_log(const char *message_format, ...)
226 {
227   va_list ap;
228   char extended_format[4096], message[4096];
229 
230   va_start(ap, message_format);
231   if (diags) {
232     NoteV(message_format, ap);
233   } else {
234     if (use_syslog) {
235       snprintf(extended_format, sizeof(extended_format), "log ==> %s", message_format);
236       vsprintf(message, extended_format, ap);
237       syslog(LOG_WARNING, "%s", message);
238     } else {
239       snprintf(extended_format, sizeof(extended_format), "[E. Mgmt] log ==> %s", message_format);
240       vsprintf(message, extended_format, ap);
241       ink_assert(fwrite(message, strlen(message), 1, stderr) == 1);
242     }
243   }
244 
245   va_end(ap);
246   return;
247 } /* End mgmt_log */
248 
249 void
mgmt_elog(const int lerrno,const char * message_format,...)250 mgmt_elog(const int lerrno, const char *message_format, ...)
251 {
252   va_list ap;
253   char extended_format[4096], message[4096];
254 
255   va_start(ap, message_format);
256 
257   if (diags) {
258     ErrorV(message_format, ap);
259     if (lerrno != 0) {
260       Error("last system error %d: %s", lerrno, strerror(lerrno));
261     }
262   } else {
263     if (use_syslog) {
264       snprintf(extended_format, sizeof(extended_format), "ERROR ==> %s", message_format);
265       vsprintf(message, extended_format, ap);
266       syslog(LOG_ERR, "%s", message);
267       if (lerrno != 0) {
268         syslog(LOG_ERR, " (last system error %d: %s)", lerrno, strerror(lerrno));
269       }
270     } else {
271       snprintf(extended_format, sizeof(extended_format), "Manager ERROR: %s", message_format);
272       vsprintf(message, extended_format, ap);
273       ink_assert(fwrite(message, strlen(message), 1, stderr) == 1);
274       if (lerrno != 0) {
275         snprintf(message, sizeof(message), "(last system error %d: %s)", lerrno, strerror(lerrno));
276         ink_assert(fwrite(message, strlen(message), 1, stderr) == 1);
277       }
278     }
279   }
280   va_end(ap);
281   return;
282 } /* End mgmt_elog */
283 
284 void
mgmt_fatal(const int lerrno,const char * message_format,...)285 mgmt_fatal(const int lerrno, const char *message_format, ...)
286 {
287   va_list ap;
288 
289   va_start(ap, message_format);
290 
291   if (diags) {
292     if (lerrno != 0) {
293       Error("last system error %d: %s", lerrno, strerror(lerrno));
294     }
295 
296     FatalV(message_format, ap);
297   } else {
298     char extended_format[4096], message[4096];
299     snprintf(extended_format, sizeof(extended_format), "FATAL ==> %s", message_format);
300     vsprintf(message, extended_format, ap);
301 
302     ink_assert(fwrite(message, strlen(message), 1, stderr) == 1);
303 
304     if (use_syslog) {
305       syslog(LOG_ERR, "%s", message);
306     }
307 
308     if (lerrno != 0) {
309       fprintf(stderr, "[E. Mgmt] last system error %d: %s", lerrno, strerror(lerrno));
310 
311       if (use_syslog) {
312         syslog(LOG_ERR, " (last system error %d: %s)", lerrno, strerror(lerrno));
313       }
314     }
315   }
316 
317   va_end(ap);
318 
319   mgmt_cleanup();
320   ::exit(1);
321 } /* End mgmt_fatal */
322 
323 static inline int
get_interface_mtu(int sock_fd,struct ifreq * ifr)324 get_interface_mtu(int sock_fd, struct ifreq *ifr)
325 {
326   if (ioctl(sock_fd, SIOCGIFMTU, ifr) < 0) {
327     mgmt_log("[getAddrForIntr] Unable to obtain MTU for "
328              "interface '%s'",
329              ifr->ifr_name);
330     return 0;
331   } else {
332 #if defined(solaris) || defined(hpux)
333     return ifr->ifr_metric;
334 #else
335     return ifr->ifr_mtu;
336 #endif
337   }
338 }
339 
340 bool
mgmt_getAddrForIntr(char * intrName,sockaddr * addr,int * mtu)341 mgmt_getAddrForIntr(char *intrName, sockaddr *addr, int *mtu)
342 {
343   bool found = false;
344 
345   if (intrName == nullptr) {
346     return false;
347   }
348 
349   int fakeSocket;            // a temporary socket to pass to ioctl
350   struct ifconf ifc;         // ifconf information
351   char *ifbuf;               // ifconf buffer
352   struct ifreq *ifr, *ifend; // pointer to individual interface info
353   int lastlen;
354   int len;
355 
356   // Prevent UMRs
357   memset(addr, 0, sizeof(struct in_addr));
358 
359   if ((fakeSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
360     mgmt_fatal(errno, "[getAddrForIntr] Unable to create socket\n");
361   }
362   // INKqa06739
363   // Fetch the list of network interfaces
364   // . from Stevens, Unix Network Prog., pg 434-435
365   ifbuf   = nullptr;
366   lastlen = 0;
367   len     = 128 * sizeof(struct ifreq); // initial buffer size guess
368   for (;;) {
369     ifbuf = static_cast<char *>(ats_malloc(len));
370     memset(ifbuf, 0, len); // prevent UMRs
371     ifc.ifc_len = len;
372     ifc.ifc_buf = ifbuf;
373     if (ioctl(fakeSocket, SIOCGIFCONF, &ifc) < 0) {
374       if (errno != EINVAL || lastlen != 0) {
375         mgmt_fatal(errno, "[getAddrForIntr] Unable to read network interface configuration\n");
376       }
377     } else {
378       if (ifc.ifc_len == lastlen) {
379         break;
380       }
381       lastlen = ifc.ifc_len;
382     }
383     len *= 2;
384     ats_free(ifbuf);
385   }
386 
387   found = false;
388   // Loop through the list of interfaces
389   ifend = reinterpret_cast<struct ifreq *>(ifc.ifc_buf + ifc.ifc_len);
390   for (ifr = ifc.ifc_req; ifr < ifend;) {
391     if (ifr->ifr_addr.sa_family == AF_INET && strcmp(ifr->ifr_name, intrName) == 0) {
392       // Get the address of the interface
393       if (ioctl(fakeSocket, SIOCGIFADDR, reinterpret_cast<char *>(ifr)) < 0) {
394         mgmt_log("[getAddrForIntr] Unable obtain address for network interface %s\n", intrName);
395       } else {
396         // Only look at the address if it an internet address
397         if (ifr->ifr_ifru.ifru_addr.sa_family == AF_INET) {
398           ats_ip_copy(addr, &ifr->ifr_ifru.ifru_addr);
399           found = true;
400 
401           if (mtu) {
402             *mtu = get_interface_mtu(fakeSocket, ifr);
403           }
404 
405           break;
406         } else {
407           mgmt_log("[getAddrForIntr] Interface %s is not configured for IP.\n", intrName);
408         }
409       }
410     }
411 #if defined(freebsd) || defined(darwin)
412     ifr = (struct ifreq *)((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
413 #else
414     ifr = reinterpret_cast<struct ifreq *>((reinterpret_cast<char *>(ifr)) + sizeof(*ifr));
415 #endif
416   }
417   ats_free(ifbuf);
418   close(fakeSocket);
419 
420   return found;
421 } /* End mgmt_getAddrForIntr */
422 
423 /*
424  * mgmt_sortipaddrs(...)
425  *   Routine to sort and pick smallest ip addr.
426  */
427 struct in_addr *
mgmt_sortipaddrs(int num,struct in_addr ** list)428 mgmt_sortipaddrs(int num, struct in_addr **list)
429 {
430   int i = 0;
431   unsigned long min;
432   struct in_addr *entry, *tmp;
433 
434   min   = (list[0])->s_addr;
435   entry = list[0];
436   while (i < num && (tmp = list[i]) != nullptr) {
437     i++;
438     if (min > tmp->s_addr) {
439       min   = tmp->s_addr;
440       entry = tmp;
441     }
442   }
443   return entry;
444 } /* End mgmt_sortipaddrs */
445 
446 void
mgmt_sleep_sec(int seconds)447 mgmt_sleep_sec(int seconds)
448 {
449   sleep(seconds);
450 }
451 void
mgmt_sleep_msec(int msec)452 mgmt_sleep_msec(int msec)
453 {
454   usleep(msec * 1000);
455 }
456