/* * Build the gmon.out file. */ void dumpstate(struct kvmvars *kvp) { register FILE *fp; struct rawarc rawarc; struct tostruct *tos; u_long frompc; u_short *froms, *tickbuf; size_t i; int mib[3]; struct gmonhdr h; int fromindex, endfrom, toindex; setprof(kvp, GMON_PROF_OFF); fp = fopen("gmon.out", "w"); if (fp == 0) { warn("gmon.out"); return; } /* * Build the gmon header and write it to a file. */ bzero(&h, sizeof(h)); h.lpc = kvp->gpm.lowpc; h.hpc = kvp->gpm.highpc; h.ncnt = kvp->gpm.kcountsize + sizeof(h); h.version = GMONVERSION; h.profrate = kvp->gpm.profrate; h.histcounter_type = kvp->gpm.histcounter_type; fwrite((char *)&h, sizeof(h), 1, fp); /* * Write out the tick buffer. */ mib[0] = CTL_KERN; mib[1] = KERN_PROF; if ((tickbuf = (u_short *)malloc(kvp->gpm.kcountsize)) == NULL) errx(5, "cannot allocate kcount space"); if (kflag) { i = kvm_read(kvp->kd, (u_long)kvp->gpm.kcount, (void *)tickbuf, kvp->gpm.kcountsize); } else { mib[2] = GPROF_COUNT; i = kvp->gpm.kcountsize; if (sysctl(mib, 3, tickbuf, &i, NULL, 0) < 0) i = 0; } if (i != kvp->gpm.kcountsize) errx(6, "read ticks: read %lu, got %ld: %s", kvp->gpm.kcountsize, (long)i, kflag ? kvm_geterr(kvp->kd) : strerror(errno)); if ((fwrite(tickbuf, kvp->gpm.kcountsize, 1, fp)) != 1) err(7, "writing tocks to gmon.out"); free(tickbuf); /* * Write out the arc info. */ if ((froms = (u_short *)malloc(kvp->gpm.fromssize)) == NULL) errx(8, "cannot allocate froms space"); if (kflag) { i = kvm_read(kvp->kd, (u_long)kvp->gpm.froms, (void *)froms, kvp->gpm.fromssize); } else { mib[2] = GPROF_FROMS; i = kvp->gpm.fromssize; if (sysctl(mib, 3, froms, &i, NULL, 0) < 0) i = 0; } if (i != kvp->gpm.fromssize) errx(9, "read froms: read %lu, got %ld: %s", kvp->gpm.fromssize, (long)i, kflag ? kvm_geterr(kvp->kd) : strerror(errno)); if ((tos = (struct tostruct *)malloc(kvp->gpm.tossize)) == NULL) errx(10, "cannot allocate tos space"); if (kflag) { i = kvm_read(kvp->kd, (u_long)kvp->gpm.tos, (void *)tos, kvp->gpm.tossize); } else { mib[2] = GPROF_TOS; i = kvp->gpm.tossize; if (sysctl(mib, 3, tos, &i, NULL, 0) < 0) i = 0; } if (i != kvp->gpm.tossize) errx(11, "read tos: read %lu, got %ld: %s", kvp->gpm.tossize, (long)i, kflag ? kvm_geterr(kvp->kd) : strerror(errno)); if (debug) warnx("lowpc 0x%lx, textsize 0x%lx", (unsigned long)kvp->gpm.lowpc, kvp->gpm.textsize); endfrom = kvp->gpm.fromssize / sizeof(*froms); for (fromindex = 0; fromindex < endfrom; ++fromindex) { if (froms[fromindex] == 0) continue; frompc = (u_long)kvp->gpm.lowpc + (fromindex * kvp->gpm.hashfraction * sizeof(*froms)); for (toindex = froms[fromindex]; toindex != 0; toindex = tos[toindex].link) { if (debug) warnx("[mcleanup] frompc 0x%lx selfpc 0x%lx " "count %ld", frompc, tos[toindex].selfpc, tos[toindex].count); rawarc.raw_frompc = frompc; rawarc.raw_selfpc = (u_long)tos[toindex].selfpc; rawarc.raw_count = tos[toindex].count; fwrite((char *)&rawarc, sizeof(rawarc), 1, fp); } } fclose(fp); }
int port_in_use(const char *if_name, unsigned eport, int proto, const char *iaddr, unsigned iport) { int found = 0; char ip_addr_str[INET_ADDRSTRLEN]; struct in_addr ip_addr; #ifdef __linux__ /* linux code */ char line[256]; FILE *f; const char * tcpfile = "/proc/net/tcp"; const char * udpfile = "/proc/net/udp"; #endif if(getifaddr(if_name, ip_addr_str, INET_ADDRSTRLEN, &ip_addr, NULL) < 0) { ip_addr.s_addr = 0; ip_addr_str[0] = '\0'; } syslog(LOG_DEBUG, "Check protocol %s for port %u on ext_if %s %s, %08X", (proto==IPPROTO_TCP)?"tcp":"udp", eport, if_name, ip_addr_str, (unsigned)ip_addr.s_addr); /* Phase 1 : check for local sockets (would be listed by netstat) */ #if defined(__linux__) f = fopen((proto==IPPROTO_TCP)?tcpfile:udpfile, "r"); if (!f) { syslog(LOG_ERR, "cannot open %s", (proto==IPPROTO_TCP)?tcpfile:udpfile); return -1; } while (fgets(line, 255, f)) { char eaddr[68]; unsigned tmp_port; if (sscanf(line, "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x " "%*x:%*x %*x %*d %*d %*llu", eaddr, &tmp_port) == 2 ) { /* TODO add IPV6 support if enabled * Presently assumes IPV4 */ #ifdef DEBUG syslog(LOG_DEBUG, "port_in_use check port %u and address %s", tmp_port, eaddr); #endif if (tmp_port == eport) { char tmp_addr[4]; struct in_addr *tmp_ip_addr = (struct in_addr *)tmp_addr; if (sscanf(eaddr,"%2hhx%2hhx%2hhx%2hhx", &tmp_addr[3],&tmp_addr[2],&tmp_addr[1],&tmp_addr[0]) == 4) { if (tmp_ip_addr->s_addr == 0 || tmp_ip_addr->s_addr == ip_addr.s_addr) { found++; break; /* don't care how many, just that we found at least one */ } } } } } fclose(f); #elif defined(__OpenBSD__) static struct nlist list[] = { #if 0 {"_tcpstat", 0, 0, 0, 0}, {"_udpstat", 0, 0, 0, 0}, {"_tcbinfo", 0, 0, 0, 0}, {"_udbinfo", 0, 0, 0, 0}, #endif {"_tcbtable", 0, 0, 0, 0}, {"_udbtable", 0, 0, 0, 0}, {NULL,0, 0, 0, 0} }; char errstr[_POSIX2_LINE_MAX]; kvm_t *kd; ssize_t n; struct inpcbtable table; struct inpcb *next; struct inpcb inpcb; kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errstr); if(!kd) { syslog(LOG_ERR, "%s: kvm_openfiles(): %s", "portinuse()", errstr); return -1; } if(kvm_nlist(kd, list) < 0) { syslog(LOG_ERR, "%s: kvm_nlist(): %s", "portinuse()", kvm_geterr(kd)); kvm_close(kd); return -1; } n = kvm_read(kd, list[(proto==IPPROTO_TCP)?0:1].n_value, &table, sizeof(table)); if(n < 0) { syslog(LOG_ERR, "%s: kvm_read(): %s", "portinuse()", kvm_geterr(kd)); kvm_close(kd); return -1; } next = CIRCLEQ_FIRST(&table.inpt_queue); /*TAILQ_FIRST(&table.inpt_queue);*/ while(next != NULL) { if(((u_long)next & 3) != 0) break; n = kvm_read(kd, (u_long)next, &inpcb, sizeof(inpcb)); if(n < 0) { syslog(LOG_ERR, "kvm_read(): %s", kvm_geterr(kd)); break; } next = CIRCLEQ_NEXT(&inpcb, inp_queue); /*TAILQ_NEXT(&inpcb, inp_queue);*/ /* skip IPv6 sockets */ if((inpcb.inp_flags & INP_IPV6) != 0) continue; #ifdef DEBUG syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu", (u_long)inpcb.inp_laddr.s_addr, ntohs(inpcb.inp_lport), (u_long)inpcb.inp_faddr.s_addr, ntohs(inpcb.inp_fport)); #endif if(eport == (unsigned)ntohs(inpcb.inp_lport)) { if(inpcb.inp_laddr.s_addr == INADDR_ANY || inpcb.inp_laddr.s_addr == ip_addr.s_addr) { found++; break; /* don't care how many, just that we found at least one */ } } } kvm_close(kd); #elif defined(__DragonFly__) const char *varname; struct xinpcb *xip; struct xtcpcb *xtp; struct inpcb *inp; void *buf = NULL; void *so_begin, *so_end; size_t len; switch (proto) { case IPPROTO_TCP: varname = "net.inet.tcp.pcblist"; break; case IPPROTO_UDP: varname = "net.inet.udp.pcblist"; break; default: syslog(LOG_ERR, "port_in_use() unknown proto=%d", proto); return -1; } if (sysctlbyname(varname, NULL, &len, NULL, 0) < 0) { syslog(LOG_ERR, "sysctlbyname(%s, NULL, ...): %m", varname); return -1; } buf = malloc(len); if (buf == NULL) { syslog(LOG_ERR, "malloc(%u) failed", (unsigned)len); return -1; } if (sysctlbyname(varname, buf, &len, NULL, 0) < 0) { syslog(LOG_ERR, "sysctlbyname(%s, buf, ...): %m", varname); free(buf); return -1; } so_begin = buf; so_end = (uint8_t *)buf + len; for (so_begin = buf, so_end = (uint8_t *)so_begin + len; (uint8_t *)so_begin + sizeof(size_t) < (uint8_t *)so_end && (uint8_t *)so_begin + *(size_t *)so_begin <= (uint8_t *)so_end; so_begin = (uint8_t *)so_begin + *(size_t *)so_begin) { switch (proto) { case IPPROTO_TCP: xtp = (struct xtcpcb *)so_begin; if (xtp->xt_len != sizeof *xtp) { syslog(LOG_WARNING, "struct xtcpcb size mismatch; %ld vs %ld", (long)xtp->xt_len, sizeof *xtp); free(buf); return -1; } inp = &xtp->xt_inp; break; case IPPROTO_UDP: xip = (struct xinpcb *)so_begin; if (xip->xi_len != sizeof *xip) { syslog(LOG_WARNING, "struct xinpcb size mismatch : %ld vs %ld", (long)xip->xi_len, sizeof *xip); free(buf); return -1; } inp = &xip->xi_inp; break; default: abort(); } /* no support for IPv6 */ if (INP_ISIPV6(inp) != 0) continue; syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu <=> %hu %08lx:%hu", (u_long)inp->inp_laddr.s_addr, ntohs(inp->inp_lport), (u_long)inp->inp_faddr.s_addr, ntohs(inp->inp_fport), eport, (u_long)ip_addr.s_addr, iport ); if (eport == (unsigned)ntohs(inp->inp_lport)) { if (inp->inp_laddr.s_addr == INADDR_ANY || inp->inp_laddr.s_addr == ip_addr.s_addr) { found++; break; /* don't care how many, just that we found at least one */ } } } if (buf) { free(buf); buf = NULL; } #elif defined(__FreeBSD__) const char *varname; struct xinpgen *xig, *exig; struct xinpcb *xip; struct xtcpcb *xtp; struct inpcb *inp; void *buf = NULL; size_t len; switch (proto) { case IPPROTO_TCP: varname = "net.inet.tcp.pcblist"; break; case IPPROTO_UDP: varname = "net.inet.udp.pcblist"; break; default: syslog(LOG_ERR, "port_in_use() unknown proto=%d", proto); return -1; } if (sysctlbyname(varname, NULL, &len, NULL, 0) < 0) { syslog(LOG_ERR, "sysctlbyname(%s, NULL, ...): %m", varname); return -1; } buf = malloc(len); if (buf == NULL) { syslog(LOG_ERR, "malloc(%u) failed", (unsigned)len); return -1; } if (sysctlbyname(varname, buf, &len, NULL, 0) < 0) { syslog(LOG_ERR, "sysctlbyname(%s, buf, ...): %m", varname); free(buf); return -1; } xig = (struct xinpgen *)buf; exig = (struct xinpgen *)(void *)((char *)buf + len - sizeof *exig); if (xig->xig_len != sizeof *xig) { syslog(LOG_WARNING, "struct xinpgen size mismatch; %ld vs %ld", (long)xig->xig_len, sizeof *xig); free(buf); return -1; } if (exig->xig_len != sizeof *exig) { syslog(LOG_WARNING, "struct xinpgen size mismatch; %ld vs %ld", (long)exig->xig_len, sizeof *exig); free(buf); return -1; } while (1) { xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); if (xig >= exig) break; switch (proto) { case IPPROTO_TCP: xtp = (struct xtcpcb *)xig; if (xtp->xt_len != sizeof *xtp) { syslog(LOG_WARNING, "struct xtcpcb size mismatch; %ld vs %ld", (long)xtp->xt_len, sizeof *xtp); free(buf); return -1; } inp = &xtp->xt_inp; break; case IPPROTO_UDP: xip = (struct xinpcb *)xig; if (xip->xi_len != sizeof *xip) { syslog(LOG_WARNING, "struct xinpcb size mismatch : %ld vs %ld", (long)xip->xi_len, sizeof *xip); free(buf); return -1; } inp = &xip->xi_inp; break; default: abort(); } /* no support for IPv6 */ if ((inp->inp_vflag & INP_IPV6) != 0) continue; syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu <=> %hu %08lx:%hu", (u_long)inp->inp_laddr.s_addr, ntohs(inp->inp_lport), (u_long)inp->inp_faddr.s_addr, ntohs(inp->inp_fport), eport, (u_long)ip_addr.s_addr, iport ); if (eport == (unsigned)ntohs(inp->inp_lport)) { if (inp->inp_laddr.s_addr == INADDR_ANY || inp->inp_laddr.s_addr == ip_addr.s_addr) { found++; break; /* don't care how many, just that we found at least one */ } } } if (buf) { free(buf); buf = NULL; } /* #elif __NetBSD__ */ #else /* TODO : NetBSD / Darwin (OS X) / Solaris code */ #error "No port_in_use() implementation available for this OS" #endif /* Phase 2 : check existing mappings * TODO : implement for pf/ipfw/etc. */ #if defined(USE_NETFILTER) if (!found) { char iaddr_old[16]; unsigned short iport_old; int i; for (i = 0; chains_to_check[i]; i++) { if (get_nat_redirect_rule(chains_to_check[i], if_name, eport, proto, iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0, 0, 0, 0, 0, 0) == 0) { syslog(LOG_DEBUG, "port_in_use check port %d on nat chain %s redirected to %s port %d", eport, chains_to_check[i], iaddr_old, iport_old); if (!(strcmp(iaddr, iaddr_old)==0 && iport==iport_old)) { /* only "in use" if redirected to somewhere else */ found++; break; /* don't care how many, just that we found at least one */ } } } } #else /* USE_NETFILTER */ UNUSED(iport); UNUSED(iaddr); #endif /* USE_NETFILTER */ return found; }