📄 netcat.c
字号:
} /* gethostpoop *//* getportpoop : Same general idea as gethostpoop -- look up a port in /etc/services, fill in global port_poop, but return the actual port *number*. Pass ONE of: pstring to resolve stuff like "23" or "exec"; pnum to reverse-resolve something that's already a number. If o_nflag is on, fill in what we can but skip the getservby??? stuff. Might as well have consistent behavior here, and it *is* faster. */USHORT getportpoop (pstring, pnum) char * pstring; unsigned int pnum;{ struct servent * servent; register int x; register int y; char * whichp = p_tcp; if (o_udpmode) whichp = p_udp; portpoop->name[0] = '?'; /* fast preload */ portpoop->name[1] = '\0';/* case 1: reverse-lookup of a number; placed first since this case is much more frequent if we're scanning */ if (pnum) { if (pstring) /* one or the other, pleeze */ return (0); x = pnum; if (o_nflag) /* go faster, skip getservbyblah */ goto gp_finish; y = htons (x); /* gotta do this -- see Fig.1 below */ servent = getservbyport (y, whichp); if (servent) { y = ntohs (servent->s_port); if (x != y) /* "never happen" */ holler ("Warning: port-bynum mismatch, %d != %d", x, y); strncpy (portpoop->name, servent->s_name, sizeof (portpoop->name)); } /* if servent */ goto gp_finish; } /* if pnum *//* case 2: resolve a string, but we still give preference to numbers instead of trying to resolve conflicts. None of the entries in *my* extensive /etc/services begins with a digit, so this should "always work" unless you're at 3com and have some company-internal services defined... */ if (pstring) { if (pnum) /* one or the other, pleeze */ return (0); x = atoi (pstring); if (x) return (getportpoop (NULL, x)); /* recurse for numeric-string-arg */ if (o_nflag) /* can't use names! */ return (0); servent = getservbyname (pstring, whichp); if (servent) { strncpy (portpoop->name, servent->s_name, sizeof (portpoop->name)); x = ntohs (servent->s_port); goto gp_finish; } /* if servent */ } /* if pstring */ return (0); /* catches any problems so far *//* Obligatory netdb.h-inspired rant: servent.s_port is supposed to be an int. Despite this, we still have to treat it as a short when copying it around. Not only that, but we have to convert it *back* into net order for getservbyport to work. Manpages generally aren't clear on all this, but there are plenty of examples in which it is just quietly done. More BSD lossage... since everything getserv* ever deals with is local to our own host, why bother with all this network-order/host-order crap at all?! That should be saved for when we want to actually plug the port[s] into some real network calls -- and guess what, we have to *re*-convert at that point as well. Fuckheads. */gp_finish:/* Fall here whether or not we have a valid servent at this point, with x containing our [host-order and therefore useful, dammit] port number */ sprintf (portpoop->anum, "%d", x); /* always load any numeric specs! */ portpoop->num = (x & 0xffff); /* ushort, remember... */ return (portpoop->num);} /* getportpoop *//* nextport : Come up with the next port to try, be it random or whatever. "block" is a ptr to randports array, whose bytes [so far] carry these meanings: 0 ignore 1 to be tested 2 tested [which is set as we find them here] returns a USHORT random port, or 0 if all the t-b-t ones are used up. */USHORT nextport (block) char * block;{ register unsigned int x; register unsigned int y; y = 70000; /* high safety count for rnd-tries */ while (y > 0) { x = (RAND() & 0xffff); if (block[x] == 1) { /* try to find a not-done one... */ block[x] = 2; break; } x = 0; /* bummer. */ y--; } /* while y */ if (x) return (x); y = 65535; /* no random one, try linear downsearch */ while (y > 0) { /* if they're all used, we *must* be sure! */ if (block[y] == 1) { block[y] = 2; break; } y--; } /* while y */ if (y) return (y); /* at least one left */ return (0); /* no more left! */} /* nextport *//* loadports : set "to be tested" indications in BLOCK, from LO to HI. Almost too small to be a separate routine, but makes main() a little cleaner... */void loadports (block, lo, hi) char * block; USHORT lo; USHORT hi;{ USHORT x; if (! block) bail ("loadports: no block?!"); if ((! lo) || (! hi)) bail ("loadports: bogus values %d, %d", lo, hi); x = hi; while (lo <= x) { block[x] = 1; x--; }} /* loadports */#ifdef GAPING_SECURITY_HOLEchar * pr00gie = NULL; /* global ptr to -e arg *//* doexec : fiddle all the file descriptors around, and hand off to another prog. Sort of like a one-off "poor man's inetd". This is the only section of code that would be security-critical, which is why it's ifdefed out by default. Use at your own hairy risk; if you leave shells lying around behind open listening ports you deserve to lose!! */doexec (fd) int fd;{ register char * p; dup2 (fd, 0); /* the precise order of fiddlage */ close (fd); /* is apparently crucial; this is */ dup2 (0, 1); /* swiped directly out of "inetd". */ dup2 (0, 2); p = strrchr (pr00gie, '/'); /* shorter argv[0] */ if (p) p++; else p = pr00gie;Debug (("gonna exec %s as %s...", pr00gie, p)) execl (pr00gie, p, NULL); bail ("exec %s failed", pr00gie); /* this gets sent out. Hmm... */} /* doexec */#endif /* GAPING_SECURITY_HOLE *//* doconnect : do all the socket stuff, and return an fd for one of an open outbound TCP connection a UDP stub-socket thingie with appropriate socket options set up if we wanted source-routing, or an unconnected TCP or UDP socket to listen on. Examines various global o_blah flags to figure out what-all to do. */int doconnect (rad, rp, lad, lp) IA * rad; USHORT rp; IA * lad; USHORT lp;{ register int nnetfd; register int rr; int x, y; errno = 0;/* grab a socket; set opts */newskt: if (o_udpmode) nnetfd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); else nnetfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (nnetfd < 0) bail ("Can't get socket"); if (nnetfd == 0) /* if stdin was closed this might *be* 0, */ goto newskt; /* so grab another. See text for why... */ x = 1; rr = setsockopt (nnetfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)); if (rr == -1) holler ("nnetfd reuseaddr failed"); /* ??? */#ifdef SO_REUSEPORT /* doesnt exist everywhere... */ rr = setsockopt (nnetfd, SOL_SOCKET, SO_REUSEPORT, &x, sizeof (x)); if (rr == -1) holler ("nnetfd reuseport failed"); /* ??? */#endif#if 0/* If you want to screw with RCVBUF/SNDBUF, do it here. Liudvikas Bukys at Rochester sent this example, which would involve YET MORE options and is just archived here in case you want to mess with it. o_xxxbuf are global integers set in main() getopt loop, and check for rr == 0 afterward. */ rr = setsockopt(nnetfd, SOL_SOCKET, SO_RCVBUF, &o_rcvbuf, sizeof o_rcvbuf); rr = setsockopt(nnetfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf);#endif /* fill in all the right sockaddr crud */ lclend->sin_family = AF_INET;/* fill in all the right sockaddr crud */ lclend->sin_family = AF_INET; remend->sin_family = AF_INET;/* if lad/lp, do appropriate binding */ if (lad) memcpy (&lclend->sin_addr.s_addr, lad, sizeof (IA)); if (lp) lclend->sin_port = htons (lp); rr = 0; if (lad || lp) { x = (int) lp;/* try a few times for the local bind, a la ftp-data-port... */ for (y = 4; y > 0; y--) { rr = bind (nnetfd, (SA *)lclend, sizeof (SA)); if (rr == 0) break; if (errno != EADDRINUSE) break; else { holler ("retrying local %s:%d", inet_ntoa (lclend->sin_addr), lp); sleep (2); errno = 0; /* clear from sleep */ } /* if EADDRINUSE */ } /* for y counter */ } /* if lad or lp */ if (rr) bail ("Can't grab %s:%d with bind", inet_ntoa(lclend->sin_addr), lp); if (o_listen) return (nnetfd); /* thanks, that's all for today */ memcpy (&remend->sin_addr.s_addr, rad, sizeof (IA)); remend->sin_port = htons (rp);/* rough format of LSRR option and explanation of weirdness.Option comes after IP-hdr dest addr in packet, padded to *4, and ihl > 5.IHL is multiples of 4, i.e. real len = ip_hl << 2. type 131 1 ; 0x83: copied, option class 0, number 3 len 1 ; of *whole* option! pointer 1 ; nxt-hop-addr; 1-relative, not 0-relative addrlist... var ; 4 bytes per hop-addr pad-to-32 var ; ones, i.e. "NOP"If we want to route A -> B via hops C and D, we must add C, D, *and* B to theoptions list. Why? Because when we hand the kernel A -> B with list C, D, Bthe "send shuffle" inside the kernel changes it into A -> C with list D, B andthe outbound packet gets sent to C. If B wasn't also in the hops list, thefinal destination would have been lost at this point.When C gets the packet, it changes it to A -> D with list C', B where C' isthe interface address that C used to forward the packet. This "records" theroute hop from B's point of view, i.e. which address points "toward" B. Thisis to make B better able to return the packets. The pointer gets bumped by 4,so that D does the right thing instead of trying to forward back to C.When B finally gets the packet, it sees that the pointer is at the end of theLSRR list and is thus "completed". B will then try to use the packet insteadof forwarding it, i.e. deliver it up to some application.Note that by moving the pointer yourself, you could send the traffic directlyto B but have it return via your preconstructed source-route. Playing withthis and watching "tcpdump -v" is the best way to understand what's going on.Only works for TCP in BSD-flavor kernels. UDP is a loss; udp_input callsstripoptions() early on, and the code to save the srcrt is notdef'ed.Linux is also still a loss at 1.3.x it looks like; the lsrr code is { }...*//* if any -g arguments were given, set up source-routing. We hit this after the gates are all looked up and ready to rock, any -G pointer is set, and gatesidx is now the *number* of hops */ if (gatesidx) { /* if we wanted any srcrt hops ... *//* don't even bother compiling if we can't do IP options here! */#ifdef IP_OPTIONS if (! optbuf) { /* and don't already *have* a srcrt set */ char * opp; /* then do all this setup hair */ optbuf = Hmalloc (48); opp = optbuf; *opp++ = IPOPT_LSRR; /* option */ *opp++ = (char) (((gatesidx + 1) * sizeof (IA)) + 3) & 0xff; /* length */ *opp++ = gatesptr; /* pointer *//* opp now points at first hop addr -- insert the intermediate gateways */ for ( x = 0; x < gatesidx; x++) { memcpy (opp, gates[x]->iaddrs, sizeof (IA)); opp += sizeof (IA); }/* and tack the final destination on the end [needed!] */ memcpy (opp, rad, sizeof (IA)); opp += sizeof (IA); *opp = IPOPT_NOP; /* alignment filler */ } /* if empty optbuf *//* calculate length of whole option mess, which is (3 + [hops] + [final] + 1), and apply it [have to do this every time through, of course] */ x = ((gatesidx + 1) * sizeof (IA)) + 4; rr = setsockopt (nnetfd, IPPROTO_IP, IP_OPTIONS, optbuf, x); if (rr == -1) bail ("srcrt setsockopt fuxored");#else /* IP_OPTIONS */ holler ("Warning: source routing unavailable on this machine, ignoring");#endif /* IP_OPTIONS*/ } /* if gatesidx *//* wrap connect inside a timer, and hit it */ arm (1, o_wait); if (setjmp (jbuf) == 0) { rr = connect (nnetfd, (SA *)remend, sizeof (SA)); } else { /* setjmp: connect failed... */ rr = -1; errno = ETIMEDOUT; /* fake it */ } arm (0, 0); if (rr == 0) return (nnetfd); close (nnetfd); /* clean up junked socket FD!! */ return (-1);} /* doconnect *//* dolisten : just like doconnect, and in fact calls a hunk of doconnect, but listens for incoming and returns an open connection *from* someplace. If we were given host/port args, any connections from elsewhere are rejected. This in conjunction with local-address binding should limit things nicely... */int dolisten (rad, rp, lad, lp) IA * rad; USHORT rp; IA * lad; USHORT lp;{ register int nnetfd; register int rr; HINF * whozis = NULL; int x; char * cp; USHORT z; errno = 0;/* Pass everything off to doconnect, who in o_listen mode just gets a socket */ nnetfd = doconnect (rad, rp, lad, lp); if (nnetfd <= 0) return (-1); if (o_udpmode) { /* apparently UDP can listen ON */ if (! lp) /* "port 0", but that's not useful */ bail ("UDP listen needs -p arg"); } else { rr = listen (nnetfd, 1); /* gotta listen() before we can get */ if (rr < 0) /* our local random port. sheesh. */ bail ("local listen fuxored"); }/* Various things that follow temporarily trash bigbuf_net, which might contain a copy of any recvfrom()ed packet, but we'll read() another copy later. *//* I can't believe I have to do all this to get my own goddamn bound address and port number. It should just get filled in during bind() or something. All this is only useful if we didn't say -p for listening, since if we said -p we *know* what port we're listening on. At any rate we won't bother with it all unless we wanted to see it, although listening quietly on a random unknown port is probably not very useful without "netstat". */ if (o_verbose) { x = sizeof (SA); /* how 'bout getsockNUM instead, pinheads?! */ rr = getsockname (nnetfd, (SA *) lclend, &x); if (rr < 0) holler ("local getsockname failed"); strcpy (bigbuf_net, "listening on ["); /* buffer reuse... */ if (lclend->sin_addr.s_addr) strcat (bigbuf_net, inet_ntoa (lclend->sin_addr)); else strcat (bigbuf_net, "any"); strcat (bigbuf_net, "] %d ..."); z = ntohs (lclend->sin_port); holler (bigbuf_net, z); } /* verbose -- whew!! *//* UDP is a speeeeecial case -- we have to do I/O *and* get the calling party's particulars all at once, listen() and accept() don't apply. At least in the BSD universe, however, recvfrom/PEEK is enough to tell us something came in, and we can set things up so straight read/write actually does work after all. Yow. YMMV on strange platforms! */ if (o_udpmode) { x = sizeof (SA); /* retval for recvfrom */ arm (2, o_wait); /* might as well timeout this, too */ if (setjmp (jbuf) == 0) { /* do timeout for initial connect */ rr = recvfrom /* and here we block... */ (nnetfd, bigbuf_net, BIGSIZ, MSG_PEEK, (SA *) remend, &x);Debug (("dolisten/recvfrom ding, rr = %d, netbuf %s ", rr, bigbuf_net)) } else goto dol_tmo; /* timeout */ arm (0, 0);/* I'm not completely clear on how this works -- BSD seems to make UDP just magically work in a connect()ed context, but we'll undoubtedly run into systems this deal doesn't work on. For now, we apparently have to issue a connect() on our just-tickled socket so we can write() back. Again, why the fuck doesn't it just get filled in and taken care of?! This hack is anything but optimal. Basically, if you want your listener
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -