1 /* $NetBSD: netcmds.c,v 1.17 2000/12/01 02:19:44 simonb Exp $ */ 2 3 /*- 4 * Copyright (c) 1980, 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)netcmds.c 8.1 (Berkeley) 6/6/93"; 40 #endif 41 __RCSID("$NetBSD: netcmds.c,v 1.17 2000/12/01 02:19:44 simonb Exp $"); 42 #endif /* not lint */ 43 44 /* 45 * Common network command support routines. 46 */ 47 #include <sys/param.h> 48 #include <sys/mbuf.h> 49 #include <sys/protosw.h> 50 51 #include <net/route.h> 52 #include <netinet/in.h> 53 #include <netinet/in_systm.h> 54 #include <netinet/ip.h> 55 #include <netinet/in_pcb.h> 56 #ifdef INET6 57 #include <netinet/ip6.h> 58 #include <netinet6/in6_pcb.h> 59 #endif 60 61 #include <arpa/inet.h> 62 63 #include <ctype.h> 64 #include <netdb.h> 65 #include <stdlib.h> 66 #include <string.h> 67 68 #include "systat.h" 69 #include "extern.h" 70 71 #define streq(a,b) (strcmp(a,b)==0) 72 73 static struct hitem { 74 struct sockaddr_storage addr; 75 int onoff; 76 } *hosts = NULL; 77 78 int nports, nhosts, protos; 79 80 static void changeitems(char *, int); 81 static void selectproto(char *); 82 static void showprotos(void); 83 static int selectport(long, int); 84 static void showports(void); 85 static int addrcmp(struct sockaddr *, struct sockaddr *); 86 static int selecthost(struct sockaddr *, int); 87 static void showhosts(void); 88 89 /* please note: there are also some netstat commands in netstat.c */ 90 91 void 92 netstat_display(char *args) 93 { 94 changeitems(args, 1); 95 } 96 97 void 98 netstat_ignore(char *args) 99 { 100 changeitems(args, 0); 101 } 102 103 void 104 netstat_reset(char *args) 105 { 106 selectproto(0); 107 selecthost(0, 0); 108 selectport(-1, 0); 109 } 110 111 void 112 netstat_show(char *args) 113 { 114 move(CMDLINE, 0); clrtoeol(); 115 if (!args || *args == '\0') { 116 showprotos(); 117 showhosts(); 118 showports(); 119 return; 120 } 121 if (strstr(args, "protos") == args) 122 showprotos(); 123 else if (strstr(args, "hosts") == args) 124 showhosts(); 125 else if (strstr(args, "ports") == args) 126 showports(); 127 else 128 addstr("show what?"); 129 } 130 131 void 132 netstat_tcp(char *args) 133 { 134 selectproto("tcp"); 135 } 136 137 void 138 netstat_udp(char *args) 139 { 140 selectproto("udp"); 141 } 142 143 static void 144 changeitems(char *args, int onoff) 145 { 146 char *cp; 147 struct servent *sp; 148 struct addrinfo hints, *res, *res0; 149 150 cp = strchr(args, '\n'); 151 if (cp) 152 *cp = '\0'; 153 for (;;args = cp) { 154 for (cp = args; *cp && isspace(*cp); cp++) 155 ; 156 args = cp; 157 for (; *cp && !isspace(*cp); cp++) 158 ; 159 if (*cp) 160 *cp++ = '\0'; 161 if (cp - args == 0) 162 break; 163 sp = getservbyname(args, 164 protos == TCP ? "tcp" : protos == UDP ? "udp" : 0); 165 if (sp) { 166 selectport(sp->s_port, onoff); 167 continue; 168 } 169 170 memset(&hints, 0, sizeof(hints)); 171 hints.ai_family = PF_UNSPEC; 172 hints.ai_socktype = SOCK_DGRAM; 173 if (getaddrinfo(args, "0", &hints, &res0) != 0) { 174 error("%s: unknown host or port", args); 175 continue; 176 } 177 for (res = res0; res; res = res->ai_next) 178 selecthost(res->ai_addr, onoff); 179 freeaddrinfo(res0); 180 } 181 } 182 183 static void 184 selectproto(char *proto) 185 { 186 187 if (proto == 0 || streq(proto, "all")) 188 protos = TCP|UDP; 189 else if (streq(proto, "tcp")) 190 protos = TCP; 191 else if (streq(proto, "udp")) 192 protos = UDP; 193 } 194 195 static void 196 showprotos(void) 197 { 198 199 if ((protos & TCP) == 0) 200 addch('!'); 201 addstr("tcp "); 202 if ((protos & UDP) == 0) 203 addch('!'); 204 addstr("udp "); 205 } 206 207 static struct pitem { 208 long port; 209 int onoff; 210 } *ports = NULL; 211 212 static int 213 selectport(long port, int onoff) 214 { 215 struct pitem *p; 216 217 if (port == -1) { 218 if (ports == NULL) 219 return (0); 220 free(ports); 221 ports = NULL; 222 nports = 0; 223 return (1); 224 } 225 for (p = ports; p < ports+nports; p++) 226 if (p->port == port) { 227 p->onoff = onoff; 228 return (0); 229 } 230 p = (struct pitem *)realloc(ports, (nports+1)*sizeof (*p)); 231 if (p == NULL) { 232 error("malloc failed"); 233 die(0); 234 } 235 ports = p; 236 p = &ports[nports++]; 237 p->port = port; 238 p->onoff = onoff; 239 return (1); 240 } 241 242 int 243 checkport(struct inpcb *inp) 244 { 245 struct pitem *p; 246 247 if (ports) 248 for (p = ports; p < ports+nports; p++) 249 if (p->port == inp->inp_lport || p->port == inp->inp_fport) 250 return (p->onoff); 251 return (1); 252 } 253 254 #ifdef INET6 255 int 256 checkport6(struct in6pcb *in6p) 257 { 258 struct pitem *p; 259 260 if (ports) 261 for (p = ports; p < ports+nports; p++) 262 if (p->port == in6p->in6p_lport || p->port == in6p->in6p_fport) 263 return (p->onoff); 264 return (1); 265 } 266 #endif 267 268 static void 269 showports(void) 270 { 271 struct pitem *p; 272 struct servent *sp; 273 274 for (p = ports; p < ports+nports; p++) { 275 sp = getservbyport(p->port, 276 protos == (TCP|UDP) ? 0 : protos == TCP ? "tcp" : "udp"); 277 if (!p->onoff) 278 addch('!'); 279 if (sp) 280 printw("%s ", sp->s_name); 281 else 282 printw("%ld ", p->port); 283 } 284 } 285 286 static int 287 addrcmp(struct sockaddr *sa1, struct sockaddr *sa2) 288 { 289 if (sa1->sa_family != sa2->sa_family) 290 return 0; 291 if (sa1->sa_len != sa2->sa_len) 292 return 0; 293 switch (sa1->sa_family) { 294 case AF_INET: 295 if (((struct sockaddr_in *)sa1)->sin_addr.s_addr == 296 ((struct sockaddr_in *)sa2)->sin_addr.s_addr) 297 return 1; 298 break; 299 #ifdef INET6 300 case AF_INET6: 301 if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)sa1)->sin6_addr, 302 &((struct sockaddr_in6 *)sa2)->sin6_addr)) 303 return 1; 304 break; 305 #endif 306 default: 307 if (memcmp(sa1, sa2, sa1->sa_len) == 0) 308 return 1; 309 break; 310 } 311 return 0; 312 } 313 314 static int 315 selecthost(struct sockaddr *sa, int onoff) 316 { 317 struct hitem *p; 318 319 if (sa == 0) { 320 if (hosts == 0) 321 return (0); 322 free((char *)hosts), hosts = 0; 323 nhosts = 0; 324 return (1); 325 } 326 for (p = hosts; p < hosts+nhosts; p++) 327 if (addrcmp((struct sockaddr *)&p->addr, sa)) { 328 p->onoff = onoff; 329 return (0); 330 } 331 if (sa->sa_len > sizeof(struct sockaddr_storage)) 332 return (-1); /*XXX*/ 333 p = (struct hitem *)realloc(hosts, (nhosts+1)*sizeof (*p)); 334 if (p == NULL) { 335 error("malloc failed"); 336 die(0); 337 } 338 hosts = p; 339 p = &hosts[nhosts++]; 340 memcpy(&p->addr, sa, sa->sa_len); 341 p->onoff = onoff; 342 return (1); 343 } 344 345 int 346 checkhost(struct inpcb *inp) 347 { 348 struct hitem *p; 349 struct sockaddr_in *sin; 350 351 if (hosts) 352 for (p = hosts; p < hosts+nhosts; p++) { 353 if (((struct sockaddr *)&p->addr)->sa_family != AF_INET) 354 continue; 355 sin = (struct sockaddr_in *)&p->addr; 356 if (sin->sin_addr.s_addr == inp->inp_laddr.s_addr || 357 sin->sin_addr.s_addr == inp->inp_faddr.s_addr) 358 return (p->onoff); 359 } 360 return (1); 361 } 362 363 #ifdef INET6 364 int 365 checkhost6(struct in6pcb *in6p) 366 { 367 struct hitem *p; 368 struct sockaddr_in6 *sin6; 369 370 if (hosts) 371 for (p = hosts; p < hosts+nhosts; p++) { 372 if (((struct sockaddr *)&p->addr)->sa_family != AF_INET6) 373 continue; 374 sin6 = (struct sockaddr_in6 *)&p->addr; 375 if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6p->in6p_laddr) || 376 IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6p->in6p_faddr)) 377 return (p->onoff); 378 } 379 return (1); 380 } 381 #endif 382 383 static void 384 showhosts(void) 385 { 386 struct hitem *p; 387 char hbuf[NI_MAXHOST]; 388 struct sockaddr *sa; 389 int flags; 390 391 #if 0 392 flags = nflag ? NI_NUMERICHOST : 0; 393 #else 394 flags = 0; 395 #endif 396 for (p = hosts; p < hosts+nhosts; p++) { 397 sa = (struct sockaddr *)&p->addr; 398 if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 399 flags) != 0) 400 strcpy(hbuf, "(invalid)"); 401 if (!p->onoff) 402 addch('!'); 403 printw("%s ", hbuf); 404 } 405 } 406