hpsockd-0.17build2/0000755000000000000000000000000011024757214011067 5ustar hpsockd-0.17build2/doc/0000755000000000000000000000000011024757214011634 5ustar hpsockd-0.17build2/doc/config.html0000644000000000000000000003216711024757214014000 0ustar

Sockd configuration file

daemon {
    negotiate-file      "filename";
  [ directory           "dirname"; ]
  [ umask               number; ]
  [ listen-address     { ifaddr; ...}; ]
  [ service             "name"; ]
  [ port                number; ]
  [ name                "name"; ]
  [ inetdsec-file       "filename"; | none; ]
  [ pre-fork            number; ]
  [ dns-helper          number; ]
  [ listen              { min, max }; ]
  [ client              { min, max }; ]
  [ user                [ "user name" | number ]; ]
  [ group               [ "group name" | number ]; ]
  [ poll                time spec; ]
  [ flags               { [ v4-only; | no-keepalive; ] }; ]
};
The daemon directive specifies global information about the daemon.  The various options mean:
 
negotiate-file Name of the negotiation file. This file is used by the various listeners to determine who listens.
directory Set working directory for sockd. Default is /var/opt/socks
umask Set umask for sockd. Default is 0o002.
listen-address Interface address(es) to listen on. Default is every configured (UP) interface, and INADDR_ANY (to catch any late additions).
service Service name used in searching inetdsec-file. Default is the service corresponding to port. If neither service nor port is specified, the service and port socks are used.
port Port number to listen on. Default is the port corresponding to service.
name Name used in syslog calls.
inetdsec-file Full path to inetd.sec. Default is none.
pre-fork Number of listening demons to initially start.
dns-helper Number of dns helper porocesses. Only applies to non-threaded platforms.
listen Minimum and maximum listening daemons.
client Minimum number of clients before a daemon stops listening, and maximum number of clients for a daemon. (It forks when it gets to the maximum.)
user User name for daemons. If a name is used and group is not specified, then the primary group for user is used.
group Group name for daemons.
poll Maximum time before a daemon checks to see if it should (or should not) be listening.
flags Any flags for daemon. v4-only disables all socks v5 functionality. (XXX -This will not be in the production version.) no-keepalive disables TCP keepalives for TCP connections (which are on by default.
The logic for a daemon to decide if it should listen is:
   if (number of clients < client.min) listen
   else if (number of clients == client.max) unlisten
   else if (at least listen.min daemons have less clients and I'm not the only listener) unlisten()

When a daemon gets client.max clients, it forks. If there are then listen.max potential listeners, the child process will never listen.

[ logging {
    [ facility          "syslog facility"; ]
    [ level             number; ]
    [ usage-log         "filename"; ]
    [ dump-prefix       "path"; ]
    [ debug             number; ]
}; ]
The logging section has the following directives:
facility One of the names from syslog.conf, such as local0.
level logging level. Currently, 2 or higher gives you a usage log, under two gives you nothing.
usage-log file name of usage log. If not specified, level  is forced to 0.
dump-prefix Prefix used for dumping configuration and clients in response to appropriate signals. The actual file name has 'conf' or 'client' and the daemon pid appended to it.
 
[ default {
    [ timeout           time spec; ]
    [ setup-timeout     time spec; ]
    [ bufsize           number; ]
}; ]
Defaults can be overridden for specific clients. The defaults are:  timeout 2h; setup-timeout 15m; bufsize 32768;
[ env {
    NAME=value;  ...
}; ]
Specify global environment variables. These are accessed from method specific routines using getEnv(). If value contains spaces or semicolons, it must be enclosed in quotes. The ping and traceroute commands rely on the environment variables PING and TRACEROUTE (respectively), in order to work. If not defined, then the client is told that the command is not supported. Suggested values are: Which use the destination IP address as the only argument to the command.
route {
    { IP4/IP4 ifaddr }; |
    { IP4/number ifaddr }; |
    { default ifaddr };
    ...
};
Routes must be specified. If the requested destination address lives on a particular route, as specified by the address/mask, then ifaddr is used in the bind call. mask can either be a CIDR mask length, or a traditional netmask. default is equivalent to 0.0.0.0/0.
method-list {
    { name "method"; number number; library "file name"; [ env { NAME=value; ... }; ] }; | 
    { name "method"; number number; internal; [env { NAME=value; ... }; ] };
    ...
};
The method list defines all of the methods available to the clients.  internal indicates that the method is built in (in the method list in method.c), otherwise the library name must be specified.  Socks V4 support requires that the "v4" method be defined.  Method numbers 0-127 are IANA assigned, 128-254 are reserved for private methods. (255 is not a legal method number.) Method specific environment variables can be specified, and are found
before the global environment variables.
client-method {
    { src { hostlist }; method { "method"; ... }; };
    ...
};
For socks clients in hostlist, the client specified method list is compared against methods, and the first match is taken. If no match is found, the request is denied.
client {
    permit|deny|skip request {
          src  { hostlist };
        [ user { "user"; ... }; ]
        [ dest { hostlist };    ]
        [ port { portlist };    ]
        [ cmd "command string"; ]
        [ timeout time spec;    ]
        [ bufsize number;       ]
    };
    ...
};
The first rule which matches the client request is used. permit grants the client's request, deny denies the request, and skip causes rule parsing to skip the next rule and continue (after possibly assigning new buffer size and timeout, as well as command execution - as specified by this rule.) Each of the specified components must match. request is one of connect, bind, udp-associate, ping, or traceroute. src and user refer to the requesting host and user, dest and port refer to the requested destination. cmd specifies a command to be executed when the rule is matched. timeout and bufsize override the global defaults when the rule is matched.
ifaddr:
    "ifname"; | hostaddr;
Interface names take precidence over hostnames, and use the IP address bound to that interface (at the time the config file is read.)
hostlist: (one or more of the following:)
    IP4/IP4; | IP4/number; | IP4; | default; | "name";
    ...
If multiple hosts (or host ranges) are specified, they are 'or' clauses.
hostaddr:
    IP4; | host; | "hostname";
In order to use host or a name, there must be only one IP address for the name given. host uses the result of gethostname() as the name of the host.
portlist:
    port; | port-port;
    ...
One or more ports.
port:
    number; | "name";
    ...
time spec:
    number[wdhms]...;
Time can be specified either as a number (of seconds), or as a collection of numbers and multipliers. For example, 1d2h specifies 1 day, 2 hours.
number:
    decimal_number | 0xhex_number |  0ooctal_number
Numbers can be specified in decimal, hex, or octal.
command string:
When a ruleset is matched, a command can be executed. This is done by forking and executing the command in the child process. The following escapes are available in command strings:
 
%A Name of source host
%a IP address of source host
%c Request type (command).
%p Process id of sockd
%S destination service name
%s destination port number
%u user name
%Z Destination host name
%z destination host address
  hpsockd-0.17build2/doc/sdc.html0000644000000000000000000000325211024757214013275 0ustar

Socks Daemon Control (sdc)

sdc is used to control the socks daemon, and display status information about it.  The following arguments are accepted:
 
status [time] Display status information on the currently listening daemons.  If time is specified, the process repeats every time seconds.
reload Cause sockd to re-read the configuration file
newlog Cause sockd to reopen the usage log.  New startup records for every active client are written.
dumpconfig Cause sockd to dump its current configuration to the file given by dump-file, with sockd's pid appended.
dumpclients Cause sockd to dump information about all active clients to the file given by client-file,  with sockd's pid appended.
unlisten Cause sockd to stop listening.  Existing connections remain open, but no new connections will be created.  Sockd will also stop listening to sdc at this point.
stop Stop sockd.  This will close any open connections.
start Launch /opt/socks/sbin/sockd
restart Equivalent to unlisten followed by start
  hpsockd-0.17build2/doc/signals.html0000644000000000000000000000213311024757214014161 0ustar

Signals

The following signals are used to signal sockd:
 

SIGHUP

Causes sockd to re-read the configuration file.   If the new configuration file fails to parse, the previous configuration remains intact.

SIGINT

Indicates that the log file has moved, and sockd should reopen its log file.  At some point, this will include rewriting the startup lines for all open connections.

SIGIOT

Indicates that sockd should no longer listen for new connections.  The listen socket is closed (meaning that a new daemon can be launched.)

SIGTERM

Close all connections and terminate.

SIGUSR1

Dump client information.
XXX - not implemented

SIGUSR2

Dump configuration.  This is done in a format that can be fed back in as a configuration file, albeit not identical to the one that was read. hpsockd-0.17build2/doc/index.html0000644000000000000000000000045011024757214013630 0ustar

HP SOCKS daemon Config file syntax /usr/sbin/sdc documentation hpsockd Signal usage hpsockd-0.17build2/src/0000755000000000000000000000000011024757214011656 5ustar hpsockd-0.17build2/src/sockd/0000755000000000000000000000000011024757214012761 5ustar hpsockd-0.17build2/src/sockd/ChangeLog0000644000000000000000000000132311024757214014532 0ustar B.05.00.%70 - First Debian build. B.05.00.%47 - Fix handling of EMFILE. B.05.00.%37 - Fix brain damage in validate on udp associate. - Add -f option to log2ascii (same as tail -f) - Get rid of 'family 0' message for connect/bind requests that terminate early. - Deal with closeConnection yanking structures out from under us, resulting in SEGV. (significant design change, coming up...) B.05.00.%35 - Fix UDP logging (show peer address, quit complaining about destination address family). - Cleanup various log messages to give a bit more detail. - Fix timeouts (this time for sure...) - Add 'skip' rules - Change 'loser' to 'nolisten' in sdc status output hpsockd-0.17build2/src/sockd/util.c0000644000000000000000000006017111024757214014107 0ustar #include "sockd.h" #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/util.c,v 0.75 2002/07/27 03:55:34 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define FREE_IF_SET(x) { if (x) { free(x); (x)=NULL; } } #define MUNMAP_IF_SET(x,s) { if (x) { munmap(x,s); (x)=NULL; } } void bufFree(dataBufType *inf) { if (inf->dataLen) { syslog(LOG_ERR,"Freeing buffer with %d byte(s) data", inf->dataLen); } MUNMAP_IF_SET(inf->bufStart,inf->bufSize); inf->bufStart=inf->dataStart=NULL; inf->bufSize=inf->dataLen=0; } /****************************************************************** * * freeSomeMemory() will release a few buffers (and resize others) * in an attempt to recover from malloc returning a NULL. ******************************************************************/ void freeSomeMemory(dataBufType *buf) { register fdInfoType *info; register int i; register long freed=0; register int thresh; #define toss(x) { freed+=(x).bufSize; bufFree(&(x)); } /* First, toss any empty output buffers */ for (i=lowFd,info=fdInfo+lowFd; i<=highFd; info++,i++) if (buf != &info->out) { if (info->out.bufStart && info->out.dataLen==0) { toss(info->out); } } if (freed>=4096) goto done; /* Then toss any empty input buffers */ for (i=lowFd,info=fdInfo+lowFd; i<=highFd; info++,i++) if (buf != &info->in) { if (info->in.bufStart && info->in.dataLen==0) { toss(info->in); } } if (freed>=4096) goto done; #undef toss /* If we didn't get any freed by now, bummer. */ if (!freed) { abort(); } done: syslog(LOG_NOTICE,"freeSomeMemory freed %d bytes",freed); } /****************************************************************** * * addToBuffer() and getFromBuffer() handle the task of adding data * to, and removing it from, a buffer (ala info->{in,out}). Saying * peek to getFromBuffer will leave the data in the buffer. * ******************************************************************/ void addToBuffer(fdInfoType *info,dataBufType *inf,void *buf,int len) { if (!inf->bufStart) { inf->bufSize=4096; inf->bufStart=mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0); inf->dataStart=inf->bufStart; inf->dataLen=0; if (!inf->bufStart) freeSomeMemory(inf); if (!inf->bufStart) { pendingClose(info,LOG_OUT_OF_MEMORY); return; } } if (inf->dataStart+inf->dataLen+len>inf->bufStart+inf->bufSize) { if (inf->dataStart != inf->bufStart) { memmove(inf->bufStart,inf->dataStart,inf->dataLen); inf->dataStart=inf->bufStart; } else { syslog(LOG_ERR, "too much data in addToBuffer(fd=%d,datalen=%d,len=%d)", info->fd,inf->dataLen,len); pendingClose(info,LOG_TOO_MUCH_TCP_DATA); return; } } memcpy(inf->dataStart+inf->dataLen,buf,len); inf->dataLen+=len; } int getFromBuffer(void *buf,dataBufType *inf,int len,int peek) { if (!inf->bufStart) return 0; if (inf->dataLendataLen; memcpy(buf,inf->dataStart,len); if (!peek) { inf->dataStart+=len; inf->dataLen-=len; if (!inf->dataLen) { inf->dataStart=inf->bufStart; } } return len; } /****************************************************************** * * setupTimeouts() and setSocketBuffer() set the initial timeouts * and buffer sizes for a socket. * ******************************************************************/ void setupTimeouts(connInfoType *conn,int timeOut) { if (!conn->startTime) conn->startTime=now; conn->timeOut=timeOut; conn->expire=timeOut ? timeOut+conn->startTime : 0; } void setSocketBuffer(int fd, int bufSize) { int bval, blen=sizeof(bval); /* set send/recv buffer sizes */ if (getsockopt(fd,SOL_SOCKET,SO_RCVBUF,&bval,&blen)==0 && bvalflags: all malloc'ed regions are freed */ bufFree(&info->in); bufFree(&info->out); shutdown(info->fd,SHUT_RDWR); close(info->fd); info->fd=-1; info->peer=NULL; info->conn=NULL; } extern int pendingCloses; void pendingClose(fdInfoType *info,int why) { register connInfoType *conn=info->conn; if (info->conn) { if (info->flags&FD_IS_LISTEN) { syslog(LOG_WARNING,"pendingClose(listen socket,%d)",why); #ifdef __hpux dumpMap(0); #endif unListen(1); return; } pendingCloses++; conn->flags|=CO_CLOSE_PENDING; conn->error=why; } else { closeConnection(info,why,1); } } /****************************************************************** * * He's dead Jim. Clean up the body, log the close record, and * handle any special beasties. * ******************************************************************/ void closeConnectionReal(fdInfoType *info,int why,int closeNow) { register connInfoType *conn=info->conn; register fdInfoType *peer=info->peer; register fdInfoType *origInfo=info; if (debug&DBG_CLOSE) { syslog(LOG_DEBUG,"closeConnection(%d,%d,%d) fd=%d flags=x%x",info-fdInfo, why, closeNow, info->fd,info->flags); } if (info->fd<0) /* we may have nuked him as part of his peer's closeConnection */ return; footprint(3,info->fd,(int)info,(int)conn); if (info->flags&FD_IS_SPECIAL) { if (info==dnsInfo) { dnsServerInit(); } else { info->flags|=FD_SHUTDOWN; clrSelect(info->fd,SL_ALL); freePointers(info); if (peer && peer->fd>=0) { peer->flags|=FD_SHUTDOWN; clrSelect(peer->fd,SL_ALL); freePointers(peer); } } return; } if (info->flags&FD_IS_LISTEN) { syslog(LOG_WARNING,"closeConnection(listen socket,%d)",why); #ifdef __hpux dumpMap(0); #endif unListen(1); return; } /* Be the client. */ info=conn->client; peer=info->peer; if (debug&DBG_CLOSE) { syslog(LOG_DEBUG," client=%d peer=%d udp=%d", conn->client-fdInfo, peer ? peer-fdInfo : -1, conn->udp ? conn->udp-fdInfo : -1); } /* If there was a udp pair for this connection, nuke it too. */ if (conn->udp) { register fdInfoType *udp,*udpPeer; udp=conn->udp, udpPeer=udp->peer; info->in.totalBytes+=udp->in.totalBytes; info->out.totalBytes+=udp->out.totalBytes; peer->in.totalBytes+=udpPeer->in.totalBytes; peer->out.totalBytes+=udpPeer->out.totalBytes; udp->flags|=FD_SHUTDOWN; clrSelect(udp->fd,SL_ALL); udpPeer->flags|=FD_SHUTDOWN; clrSelect(udpPeer->fd,SL_ALL); freePointers(udp); freePointers(udpPeer); conn->udp=NULL; } info->flags|=FD_SHUTDOWN; clrSelect(info->fd,SL_ALL); peer->flags|=FD_SHUTDOWN; clrSelect(peer->fd,SL_ALL); if (!closeNow && conn->req && (info->out.dataLen || peer->out.dataLen)) { if (info->out.dataLen) setSelect(info->fd,SL_WRITE); if (peer->out.dataLen) setSelect(peer->fd,SL_WRITE); return; } if (conn->pid) { kill(conn->pid,SIGKILL); conn->pid=0; } if (!info->conn) { syslog(LOG_ERR,"Null connection pointer origInfo=%x conn=%x info=%x",origInfo,conn,info); #ifdef __hpux dumpMap(0); #endif unListen(1); return; } else { logClose(info, why); } freePointers(info); freePointers(peer); FREE_IF_SET(conn->user); FREE_IF_SET(conn->req); conn->flags &= ~CO_IN_USE; conn->client=(fdInfoType*)freeConn; freeConn=conn; if (!--negotInfo->numConn && (negotInfo->flags&NF_LOSER)) destroyDaemon(); else { tryListen(0); while (fdInfo[highFd].fd == -1 && highFd>lowFd) --highFd; while (fdInfo[lowFd].fd == -1 && highFd>lowFd) ++lowFd; } } int insane_count=0; void insane(int where) { static int logged=0; if (!logged) { syslog(LOG_ERR, "insane internal structures: %d",where); dumpFootprint(where); } logged=1; insane_count++; } void connSanity(int call) { register fdInfoType *info, *client; register connInfoType *conn; if (!(debug&DBG_SANITY)) return; for (info=fdInfo; infoflags&=~FD_SANITY_HIT; for (conn=connInfo; connflags&=~CO_SANITY_HIT; for (info=fdInfo; infoconn; if (info->fd<0 || !conn) continue; if (!(conn->flags&CO_IN_USE)) { syslog(LOG_ERR,"using unused connection info=%x, conn=%x",info,conn); insane(1); } info->flags |= FD_SANITY_HIT; if (info->peer->conn != conn || info->peer->peer != info) insane(2); if (info->flags&FD_IS_CLIENT) { if (info->flags&FD_IS_UDP) { if (conn->udp != info) insane(3); } else { if (conn->client != info) insane(4); } if (conn->udp && conn->udp->conn != conn) insane(5); } } for (conn=freeConn; conn; conn=(connInfoType*)conn->client) { if (conn->flags&CO_IN_USE) { syslog(LOG_ERR,"free conn(%x) in use",conn); insane(6); } conn->flags |= CO_SANITY_HIT; } for (conn=connInfo; connflags & (CO_SANITY_HIT|CO_IN_USE)) == 0) { syslog(LOG_ERR,"lost conn(%x)",conn); insane(7); } if (conn->flags&CO_IN_USE) { if (conn->client->conn != conn || !(conn->client->flags&FD_SANITY_HIT)) { syslog(LOG_ERR,"badly broken connection %x",conn); insane(8); } } } } void closeConnection(fdInfoType *info,int why,int closeNow) { connSanity(0); closeConnectionReal(info,why,closeNow); connSanity(1); } int createSocket(int af, int type, int protocol) { register int fd=socket(af,type,protocol); int val=((config.daemon.flags&FL_NO_KEEPALIVE)==0); if (fd<0) return fd; bumpHighLow(fd); setNonBlocking(fd); if (type==SOCK_STREAM) { if (setsockopt(fd,SOL_SOCKET,SO_KEEPALIVE,&val,sizeof(val))<0) syslog(LOG_NOTICE,"setsockopt(SO_KEEPALIVE) failed %m"); val=1; if (setsockopt(fd,SOL_SOCKET,SO_OOBINLINE,&val,sizeof(val))<0) syslog(LOG_NOTICE,"setsockopt(SO_OOBINLINE) failed %m"); } return fd; } extern fd_set readFds,writeFds,excpFds; /*********************************************************************** * setSelect(int fd,int which) * clrSelect(int fd,int which) * * Set select flags for mainLoop(). ***********************************************************************/ void setSelect(int fd, int which) { bumpHighLow(fd); #if 0 footprint(0xa,fd,which,0); #endif if (which&SL_READ) { FD_SET(fd,&readFds); } if (which&SL_WRITE) { FD_SET(fd,&writeFds); } if (which&SL_EXCP) { FD_SET(fd,&excpFds); } } void clrSelect(int fd, int which) { #if 0 footprint(0x1a,fd,which,0); #endif if (which&SL_READ) { FD_CLR(fd,&readFds); } if (which&SL_WRITE) { FD_CLR(fd,&writeFds); } if (which&SL_EXCP) { FD_CLR(fd,&excpFds); } } /****************************************************************** * * nullExcp is an exception handler for people who don't need * one. Sometime down the road, we'll need to handle out of band * data. As it sits, we just close the connection. * ******************************************************************/ void nullExcp(fdInfoType *info) { syslog(LOG_NOTICE,"Exception on %d",info->fd); /* XXX */ pendingClose(info,LOG_OOB_DATA_NOT_SUPP); /* XXX */ } /****************************************************************** * * setupDaemon() does all of the setup work for a newly hatched * daemon. If possible, this daemon will compete for new * connections, just like his daddy and other relatives. If he * can't get a slot in the negotiation table, then he is a loser. * (I know, that's really negative. Bummer.) * ******************************************************************/ negotInfoType loserInfo; void setupDaemon(int numConn) { register int i; register negotInfoType *nInfo; register int loser=0; char cmdLine[256]; setupSignals(1); negotInfo=NULL; /* That one belongs to daddy. */ negotLock(); for (i=0,nInfo=negot->slot;ipid) checkPidLock(i); if (!nInfo->pid) { negotSlot=i; negotInfo=nInfo; break; } } if (!negotInfo) { loser=1; nInfo=negotInfo=&loserInfo; nInfo->flags|=NF_LOSER; } nInfo->pid=getpid(); nInfo->flags=0; nInfo->numConn=numConn; nInfo->lastChecked=time(NULL); tryListen(1); negotUnlock(); if (loser) { unListen(1); if (!numConn) destroyDaemon(); } else { snprintf(cmdLine,sizeof(cmdLine),"%s --listen",config.daemon.name); setCommandLine(cmdLine); dnsServerInit(); } } void forgetInfo(fdInfoType *info) { if (info->in.bufStart) bufFree(&info->in); if (info->out.bufStart) bufFree(&info->out); info->conn=NULL; close(info->fd); clrSelect(info->fd,SL_ALL); info->fd=-1; } static void forgetConn(connInfoType *conn) { fdInfoType *infos[5], *info; register int i=0; infos[i++]=conn->client; if (conn->client->peer) infos[i++]=conn->client->peer; if (conn->udp) { infos[i++]=conn->udp; if (conn->udp->peer) infos[i++]=conn->udp->peer; } infos[i]=NULL; for (i=0;infos[i]; i++) { forgetInfo(infos[i]); } conn->startTime=0; conn->flags &= ~CO_IN_USE; conn->client=(fdInfoType*)freeConn; freeConn=conn; } /****************************************************************** * * spawnChild() forks the daemon, and gives the child all of the * clients. The parent is then free to continue on with his life. * ******************************************************************/ int spawnChild(connInfoType *conn) { register int numConn=negotInfo->numConn; register int ret; register int fd; ret=fork(); switch(ret) { register int i; register fdInfoType *info; case 0: /* Child keeps all the active connections, except maybe 1 */ if ((debug&DBG_CHILD) && (debug&DBG_FOREGROUND)) { volatile int dbg_wait=0; while (!dbg_wait); } footprint(0x16,highFd,(int)conn,0); if (conn) { forgetConn(conn); numConn--; } setupDaemon(numConn); break; case -1: syslog(LOG_ERR,"fork failed: %m"); return -1; default: footprint(6,highFd,(int)conn,0); connSanity(6); for (i=lowFd,info=fdInfo+lowFd; i<=highFd; i++,info++) { if (info->fd!=-1) { if (info->conn != conn && !(info->flags&FD_IS_LISTEN)) { forgetConn(info->conn); } else { fd=i; } } } highFd=fd; negotInfo->numConn=conn ? 1 : 0; } return ret; } /****************************************************************** * * We're dead, Jim. Close the door and turn out the lights. * ******************************************************************/ static int inDestroy=0; void destroyDaemon(void ) { dnsDestroy(); if (!inDestroy && negotInfo->numConn) { inDestroy=1; terminate(0); } if (negotInfo!=&loserInfo) { unListen(1); negotLock(); negotInfo->pid=0; negotUnlock(); } exit(0); } /****************************************************************** * * Here begins the negotiation routines. On machines that support * memory mapped files, we use one of those. Otherwise, we use * a shared memory segment. * * negotInit() is the guy who sets up the table initially, so that * everyone can play with it once we start launching daemon children. * ******************************************************************/ int negotFd; void negotInit(void) { char blank[NEGOT_SIZE]; register int created=0; /* setup multi-daemon negotiation page */ negotFd=open(config.daemon.negotFile,O_RDWR); if (negotFd<0) { if ((negotFd=open(config.daemon.negotFile,O_WRONLY|O_CREAT|O_EXCL,0644))>=0) { memset(blank,0,sizeof(blank)); write(negotFd,blank,sizeof(blank)); close(negotFd); negotFd=open(config.daemon.negotFile,O_RDWR); created=1; } if (negotFd<0) { syslog(LOG_ERR,"Unable to open negotiation file: %m"); exit(2); } } #ifdef HAVE_MMAP negot=(negotPageType*)mmap((void*)NULL,NEGOT_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_FILE,negotFd,0); #define CHECK(negot) (negot)==(negotPageType*)0xffffffff || !(negot) #define ERRSTR "Unable to mmap negotiation file: %m" #else { int key; int shmId; key=ftok(config.daemon.name,ntohs(config.daemon.port)); shmId=shmget(key,NEGOT_SIZE,IPC_CREAT|0644); if (shmId>=0) { negot=(negotPageType*)shmat(shmId,NULL,0); } else { negot=NULL; } } #define CHECK(negot) !(negot) #define ERRSTR "Unable to attach negotiation shared memory: %m" #endif if (CHECK(negot)) { syslog(LOG_ERR,ERRSTR); exit(2); } else { register int i; if (created) { memset((void*)negot,0,NEGOT_SIZE); #ifdef HAVE_MSEM msem_init(&negot->head.sema,MSEM_UNLOCKED); #else { struct semid_ds buf; int val=1; negot->head.semId=semget(ftok(config.daemon.name,ntohs(config.daemon.port)),1,IPC_CREAT|0600); semctl(negot->head.semId,0,SETVAL,val); } #endif for (i=0;islot[i].pid=0; negot->slot[i].numConn=0; } } } } /****************************************************************** * * negotLock() acquires exclusive access to the negotiation table. * This is useful for inserting yourself, or making sure that only * one daemon scans things at a time. Note that updates to your * own slot's numConn are not protected by the semaphore. Those * are read only for everyone else. * ******************************************************************/ void negotLock(void) { #ifdef HAVE_MSEM register int ret; ret=msem_lock(&negot->head.sema,0); if (ret<0) { syslog(LOG_ERR,"msem_lock: %m"); exit(2); } #else struct sembuf sops[1]; register int res; sops[0].sem_num=0; sops[0].sem_op=-1; sops[0].sem_flg=0; res=semop(negot->head.semId,sops,1); #endif } /****************************************************************** * * negotUnlock() releases exclusive access to the negotiation table. * What we take, we must give back. * ******************************************************************/ void negotUnlock(void) { #ifdef HAVE_MSEM if (msem_unlock(&negot->head.sema,0)<0) { syslog(LOG_ERR,"msem_unlock: %m"); exit(2); } #else struct sembuf sops[1]; register int res; sops[0].sem_num=0; sops[0].sem_op=1; sops[0].sem_flg=0; res=semop(negot->head.semId,sops,1); #endif } /****************************************************************** * * Compare a host entry to an address, and see if it's a hit. * ******************************************************************/ int compareAddr(hostType *host, u_int32_t IP) { register int t=ntohl(IP&host->mask); switch(host->op) { case r_eq: return t==ntohl(host->value); case r_ne: return t!=ntohl(host->value); case r_lt: return t< ntohl(host->value); case r_le: return t<=ntohl(host->value); case r_gt: return t> ntohl(host->value); case r_ge: return t>=ntohl(host->value); default: return 0; } } /****************************************************************** * * At this point, we're down to the utilitiy routines again, so * there isn't much logic to the ordering of things... Not that * there's that much order elsewhere, but I tried. * * findRoute takes a destination IP address and figures out what * the source IP address for the bind should be. * * XXX IPV6 - This needs to handle IP V6 addresses as well... * ******************************************************************/ u_int32_t findRoute(u_int32_t destIP) { register routeInfoType *route=config.routes.list; register int i; for (i=config.routes.num;i>0;i--,route++) { if (compareAddr(&route->host,destIP)) return route->ip; } return INADDR_ANY; } /****************************************************************** * * Get an environment variable for a connection. We first look * in the method specific environment, and then move on to the * global environment. * ******************************************************************/ const char *getEnv(const fdInfoType *info,const char *name) { register int len=strlen(name); register char **env; register int i; /* first look at the method specific environment */ for (i=info->conn->method->env.num-1,env=info->conn->method->env.list;i>= 0; i--,env++) { if (strncmp(name,*env,len)==0 && env[0][len]=='=') { return *env+len+1; } } /* then look at the global environment */ for (i=config.env.num-1,env=config.env.list;i>= 0; i--,env++) { if (strncmp(name,*env,len)==0 && env[0][len]=='=') { return *env+len+1; } } /* XXX - Maybe do a getenv()? */ return NULL; } /****************************************************************** * footprinting code. ******************************************************************/ #define FP_NUM 3000 int fp_num=FP_NUM; struct fp { time_t time; unsigned short a,b; int c,d; } fp[FP_NUM]; int fp_next=0; void footprint(u_short a, u_short b, int c, int d) { fp[fp_next].time=time(NULL); fp[fp_next].a=a; fp[fp_next].b=b; fp[fp_next].c=c; fp[fp_next].d=d; if (fp_next++ >= fp_num) fp_next=0; } void dumpFootprint(int where) { register int fd; register char *base=config.log.dumpPrefix; register char *name; register int i; register fdInfoType *info; register connInfoType *conn; register FILE* f; if (!base) { syslog(LOG_ERR,"No dump file."); return; } name=malloc(strlen(base)+30); if (name==NULL) { freeSomeMemory(NULL); name=malloc(strlen(base)+30); } if (name==NULL) { syslog(LOG_ERR,"Out of memory in dumpFootprint"); return; } sprintf(name,"%s.footprint.%d",base,negotInfo->pid); fd=open(name,O_WRONLY|O_CREAT|O_EXCL,0600); if (fd<0) { syslog(LOG_ERR,"Couldn't open %s for write",name); free(name); return; } f=fdopen(fd,"w"); fprintf(f,"where=%d\n",where); i=fp_next ? fp_next-1 : fp_num-1; while (i!= fp_next) { if (fp[i].time) fprintf(f,"%04x %4d 0x%08x 0x%08x %s", /* ctime has \n */ fp[i].a, fp[i].b, fp[i].c, fp[i].d, ctime(&fp[i].time)); i= i ? i-1 : fp_num-1; } fprintf(f,"\nfdInfo:\n"); fprintf(f," addr peer conn fd flags IPaddr port\n"); fprintf(f,"======== ======== ======== ======== ======== ======== =====\n"); for (info=fdInfo; infopeer,info->conn,info->fd,info->flags, ntohl(info->sin.sin_addr.s_addr),ntohs(info->sin.sin_port)); } fprintf(f,"\nconnInfo:\n"); fprintf(f," addr client udp flags error\n"); fprintf(f,"======== ======== ======== ======== ========\n"); for (conn=connInfo; connclient,conn->udp,conn->flags,conn->error); } fclose(f); free(name); } /****************************************************************** * * How do I set the command line? Let me count the ways. * ******************************************************************/ #ifdef __hpux #include #define HAVE_PSTAT #endif void setCommandLine(char *s) { #ifdef HAVE_PSTAT /* [ */ union pstun pst; pst.pst_command=s; pstat(PSTAT_SETCMD,pst,0,0,0); return; #else /* ] ! HAVE_PSTAT [ */ /* XXX - need non-PSTAT setCommandLine */ #endif /* ] ! HAVE_PSTAT */ } hpsockd-0.17build2/src/sockd/sockd.conf.template0000644000000000000000000000304011024757214016542 0ustar daemon { # name "sockd"; # listen-address { 0.0.0.0; }; # directory "/var/opt/socks"; negotiate-file "negot_file"; # must be specified inetdsec-file "@@INETDSEC@@"; # default is no inetd.sec # listen {1,252}; # client {1,200}; # pre-fork 1; # service "socks"; # port 1080; # poll 1m; # user -2; user "socks"; # dns-helper 1; # flags { }; }; logging { # facility "daemon"; # level 2; dump-prefix "sockd.dump"; # if not specified, you get no dumps usage-log "usage.log"; # if not specified, you get no logging }; env { PING="@@PING@@ %z"; TRACEROUTE="@@TRACEROUTE@@ %z"; }; default { # timeout 2h; # setup-timeout 15m; # bufsize 32768; }; route { { default host }; # must have at least one route }; method-list { { number 0; name "noAuth"; internal; flags 0; }; { number 2; name "userPass"; internal; flags 0; }; { number 254; name "v4"; internal; flags 0; }; }; client-method { { src { @@MYNET@@/@@NETSIZE@@; }; method { "userPass"; "v4"; "noAuth"; }; }; }; client { permit traceroute { # Let net @@MYNET@@ traceroute even net @@MYNET@@. src { @@MYNET@@/@@NETSIZE@@; }; }; deny { # block X traffic port { 6000-6099; }; }; deny { # Nothing bound for net @@MYNET@@, or private dest { @@MYNET@@/@@NETSIZE@@; 127/8; 10/8; 172.16/12; 192.168/16; }; }; permit { # give ftp control sessions longer src { @@MYNET@@/@@NETSIZE@@; }; port { "ftp"; }; timeout 1d; }; permit { # Let net @@MYNET@@ out src { @@MYNET@@/@@NETSIZE@@; }; timeout 1h; }; deny { }; # nuke everyone else (default action) }; hpsockd-0.17build2/src/sockd/methods.c0000644000000000000000000000712311024757214014573 0ustar #include "sockd.h" #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/methods.c,v 0.13 2000/12/08 20:47:24 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_SHL_LOAD #include "dl.h" #elif defined(HAVE_DLOPEN) #include #endif intMethInfoType intMethods[]= { { "v4", v4Info }, { "noAuth", noAuthInfo}, { "userPass", userPassInfo}, { NULL, NULL} }; int loadMethInfo(methodInfoType *mInfo) { register intMethInfoType *meth=intMethods; register char *name=mInfo->name; mInfo->info=NULL; #ifdef FULLMETHOD mInfo->recv=recv; mInfo->send=send; mInfo->excp=nullExcp; #endif mInfo->inboundUdp=v5InboundUdpReq, mInfo->outputUdp=v5OutputUdpReply; mInfo->recvFrom=(recvFromFunc*)recvfrom, mInfo->sendTo=(sendToFunc*)sendto; if (mInfo->libName) { register char *infoName; #ifdef HAVE_SHL_LOAD shl_t handle=shl_load(mInfo->libName,BIND_IMMEDIATE,0); #elif defined(HAVE_DLOPEN) void *handle=dlopen(mInfo->libName,RTLD_NOW); #else void *handle; return -1; #endif if (!handle) return -1; infoName=malloc(strlen(name)+5); if (infoName==NULL) { syslog(LOG_ERR,"Out of memory in loadMethInfo"); return -1; } sprintf(infoName,"%sInfo",name); #ifdef HAVE_SHL_LOAD if (shl_findsym(&handle,infoName,TYPE_PROCEDURE,&mInfo->info)<0) { #elif defined(HAVE_DLOPEN) if (!(mInfo->info=(infoFunc*)dlsym(handle,infoName))) { #else { #endif free(infoName); return -1; } free(infoName); } else { while (meth->name) { if (strcmp(meth->name,name)==0) { mInfo->info=meth->info; break; } meth++; } if (!mInfo->info) return -1; } return mInfo->info(mInfo,METHOD_VERSION); } /******************************************************************************************** * Find the method that we will agree to use for this client. Once we find a source that * matches the client, we run through that method list until we find one that is included * in methData (from the client). If we don't find anything, we leave. * * The v4 code passes in a version of SOCKS_V4, 1 method, "v4". *******************************************************************************************/ methodInfoType *findMatchingMethod(struct sockaddr_in *sin,u_char *methData) { register int i,j,k,l; for (i=0;isin_addr.s_addr)) { /* Find the first method that is in methData */ for (k=0;knum; for (l=0;l=0)? (negotPageType*)shmat(shmId,NULL,0) : NULL; if (negotTmp) { negot=malloc(NEGOT_SIZE); if (negot==NULL) { syslog(LOG_ERR,"Out of memory"); exit(1); } memcpy(negot,negotTmp,NEGOT_SIZE); shmdt(negotTmp); } } #endif if (negot==(negotPageType*)0xffffffff || !negot) { perror("negot mmap()"); exit(1); } if (!pGroup) pGroup=-negot->head.processGroup; signal=0; if (strcmp(*argv,"status")==0) { register int wait=0; if (argc>1) wait=strtol(argv[1],NULL,10); doStatus(wait); return 0; } else if (strcmp(*argv,"reload")==0) { signal=SIGHUP; } else if (strcmp(*argv,"newlog")==0) { signal=SIGINT; } else if (strcmp(*argv,"dumpconfig")==0 || strcmp(*argv,"config")==0) { signal=SIGUSR2; } else if (strcmp(*argv,"dumpclient")==0 || strcmp(*argv,"client")==0) { signal=SIGUSR1; doClients(); } else if (strcmp(*argv,"stop")==0) { signal=SIGTERM; } else if (strcmp(*argv,"start")==0) { register char *c=strrchr(SOCKD_PATH,'/')+1; execl(SOCKD_PATH,c,(char*)NULL); perror("exec failed"); } else if (strcmp(*argv,"unlisten")==0) { signal=SIGEMT; } else if (strcmp(*argv,"restart")==0) { register int ret=kill(pGroup,SIGEMT); register char *c=strrchr(SOCKD_PATH,'/')+1; if (ret<0) { perror("failed to deliver signal"); return 1; } sleep(2); execl(SOCKD_PATH,c,(char*)NULL); perror("exec failed"); } else { usage: fprintf(stderr, "usage: %s [-c config] status [interval]|reload|newlog|dumpconfig|dumpclient|unlisten|stop|start|restart\n", name); return 2; } if (signal) { register int ret=kill(pGroup,signal); if (ret<0) { perror("failed to deliver signal"); return 1; } } return 0; } const char *printFlags(int flags) { static char buf[12]; if (flags==NF_LOSER) { return "nolisten"; } else if (!flags) { return ""; } else { snprintf(buf,sizeof(buf),"0x%08x",flags); return buf; } } doStatus(int wait) { register int i; register int highSlot=NEGOT_MAXSLOT; register int highListen; register negotInfoType *nInfo; for (nInfo=negot->slot+highSlot-1;!nInfo->pid && highSlot>0;highSlot--,nInfo--); for (highListen=highSlot,nInfo=negot->slot+highListen-1; ((nInfo->flags&NF_LOSER) || !nInfo->pid) && highListen>0; highListen--,nInfo--); do { printf("process group=%d\n",negot->head.processGroup); printf("listeners: %d (min=%d max=%d)\n",negot->head.numListen,config.daemon.minListen, config.daemon.maxListen); for (i=0;ihead.listeners)/sizeof(negot->head.listeners[0]);i++) { printf("0x%08x ",negot->head.listeners[i]); if ((i+1)*sizeof(negot->head.listeners[0])*8 >= highSlot) break; } putchar('\n'); for (i=0,nInfo=negot->slot;ipid) { printf("%3d: %5d %5d %10s %s",i,nInfo->pid,nInfo->numConn,printFlags(nInfo->flags),ctime(&nInfo->lastChecked)); } if (!negot->head.numListen) /* all gone, time to leave... */ wait=0; } while (wait>0 && sleep(wait)==0); return 0; } void doClients(void) { sleep(1); /* give them some time to complete */ /* XXX - fork/exec log2ascii on each dump file */ } int loadMethInfo(methodInfoType *mInfo) { return 0; } /* keep gram.y happy */ void freeSomeMemory(dataBufType *buf) { fprintf(stderr,"out of memory!!??\n"); exit(1); } hpsockd-0.17build2/src/sockd/v5tcp.c0000644000000000000000000001656211024757214014200 0ustar #include "sockd.h" #include "v5.h" #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/v5tcp.c,v 0.24 2002/07/27 03:55:34 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /************************************************************************* * simpleInbound() is handed a buffer of unprocessed input data from recv(), * which it must completely consume, possibly into info->in. *************************************************************************/ void simpleInbound(fdInfoType *info,void *buf,int len,unsigned int flags) { register fdInfoType *peer=info->peer; /* if there is no data queued, just toss it across. */ if (!info->in.dataLen) { if (peer->TCP_OUTPUT(peer,buf,len,flags)>0) { clrSelect(info->fd,SL_READ); } } else { /* We have data queued, and should handle it. */ addToBuffer(info,&info->in,buf,len); if (peer->TCP_OUTPUT(peer,info->in.dataStart,info->in.dataLen,flags)>0) { clrSelect(info->fd,SL_READ); } info->in.dataLen=0; bufFree(&info->in); } } /************************************************************************* * simpleOutput() is handed a buffer of unencapsulated data to be packed * and sent, which it must completely consume, possibly into info->out. * If data is queued in out (only because of a partial write to the * socket, then the write select flag must be set by output(). The * outer loop will then do the write() calls itself. * Returns * 0 for all OK, * 1 if the inbound side should hold off sending more data * -1 if there was an error (the inbound side is already shut down at * that point.) *************************************************************************/ int simpleOutput(fdInfoType *info,void *ubuf,int len,unsigned int flags) { register char *buf=ubuf; register int xfr; xfr=info->TCP_SEND(info->fd,buf,len,flags); if (xfr<0) { if (errno==EWOULDBLOCK) { xfr=0; } else { pendingClose(info,LOG_ERRNO+errno); return -1; } } updateTime(info,out,xfr,now); if (xfr != len) { addToBuffer(info,&info->out,buf+xfr,len-xfr); setSelect(info->fd,SL_WRITE); clrSelect(info->peer->fd,SL_READ); return 1; } else { if (info->peer->sin.sin_addr.s_addr) { setSelect(info->peer->fd,SL_READ); } return 0; } } int v5DoConnect(fdInfoType *client) { register fdInfoType *peer=client->peer; register connInfoType *conn=client->conn; register int outFd=peer->fd,res; struct sockaddr_in sin; register v5HeadType *req=conn->req; register int ret; outFd=peer->fd; if ((ret=v5GetSin(req,&sin,sizeof(sin)))!= SOCKS5_OK) return ret; peer->sin=sin; peer->TCP_INBOUND=simpleInbound; peer->TCP_OUTPUT =simpleOutput; clrSelect(client->fd,SL_READ); res=connect(outFd,(struct sockaddr*)&sin,sizeof(sin)); if (res==0 || res<0 && errno==EINPROGRESS) { peer->TCP_SEND=v5ConnectSendReply; setSelect(outFd,SL_WRITE); clrSelect(outFd,SL_READ); } else { v5ConnectSendReply(outFd,NULL,0,0); /* just send it now */ } return SOCKS5_OK; /* so far, anyway. (Or we already closed out the connection.) */ } /* sendFunc */ /* ARGSUSED */ ssize_t v5ConnectSendReply(int fd, const void *buf,size_t count,unsigned int flg) { register fdInfoType *peer=fdInfo+fd; register fdInfoType *client=peer->peer; register int res; struct sockaddr_in sin; int sinlen=sizeof(peer->sin); if (client->fd<0) return 0; peer->TCP_SEND=(sendFunc*)send; peer->TCP_INBOUND=simpleInbound; res=connect(fd,(struct sockaddr*)&client->sin,sizeof(client->sin)); footprint(9,client->fd,errno,0); memset(&peer->sin,0,sizeof(peer->sin)); if (res==0 || errno==EISCONN) { sinlen=sizeof(sin); res=getsockname(fd,(struct sockaddr*)&sin,&sinlen); sinlen=sizeof(peer->sin); res=getpeername(fd,(struct sockaddr*)&peer->sin,&sinlen); v5WriteReply(client,&sin,SOCKS5_OK,0); if (client->fd>=0) { setSelect(client->fd,SL_READ); setSelect(fd,SL_READ|SL_EXCP); } } else { v5WriteReply(client,&client->sin,v5ErrnoToResult(errno),0); if (client->fd>=0) pendingClose(peer,LOG_ERRNO+errno); } return 0; } int v5DoBind(fdInfoType *client) { register fdInfoType *peer=client->peer; register connInfoType *conn=client->conn; register int outFd=peer->fd,res; struct sockaddr_in sin; register v5HeadType *req=conn->req; double dbuf[304/sizeof(double)]; outFd=peer->fd; switch(conn->req->atyp) { case ATYP_V4: { u_int32_t dest; memcpy(&dest,req->destAddr,sizeof(dest)); memset(&sin,0,sizeof(sin)); sin.sin_family=AF_INET; sin.sin_addr.s_addr=findRoute(dest); memcpy(&sin.sin_port,req->destAddr+4,sizeof(sin.sin_port)); if (ntohs(sin.sin_port)TCP_RECV=v5BindRecv; return SOCKS5_OK; /* So far, anyway. */ } /* recvFunc */ /* ARGSUSED */ ssize_t v5BindRecv(int fd, void *buf,size_t count,unsigned int flags) { register fdInfoType *peer=fdInfo+fd; register fdInfoType *client=peer->peer; register connInfoType *conn=peer->conn; int sinlen=sizeof(peer->sin); register int newFd; register int result; newFd=accept(fd,(struct sockaddr*)&peer->sin,&sinlen); if (newFd>=0) { dup2(newFd,fd); close(newFd); setSocketBuffer(fd,conn->bufSize); setNonBlocking(fd); peer->TCP_RECV=(recvFunc*)recv; result=SOCKS5_GENFAIL; switch(peer->sin.sin_family) { case AF_INET: if (memcmp(&conn->req->destAddr,&peer->sin.sin_addr,4)==0) { result=SOCKS5_OK; } else { unsigned int destAddr; memcpy(&destAddr,conn->req->destAddr,sizeof(destAddr)); syslog(LOG_ERR,"v5BindRecv received connection from %s, expected connection from %s", inetNtoa(peer->sin.sin_addr.s_addr), inetNtoa(destAddr)); } break; #ifdef AF_INET6 case AF_INET6: if (memcmp(&conn->req->destAddr,&peer->sin.sin_addr,16)==0) result=SOCKS5_OK; break; #endif default: result=SOCKS5_ADDR_NOT_SUPP; break; } } else { syslog(LOG_WARNING,"v5BindRecv accept failed: %m"); result=v5ErrnoToResult(errno); } setSelect(fd,SL_READ|SL_EXCP); v5WriteReply(client,&peer->sin,result,0); return result==SOCKS5_OK ? -2 : -1; } hpsockd-0.17build2/src/sockd/paths.h0000644000000000000000000000175611024757214014262 0ustar /* USERPASSDB_PATH is the path to the user/pass database, built with * makepass hash userpass < userpass */ /* (c) Copyright Hewlett-Packard Company 1997-2000. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define USERPASSDB_PATH "/etc/opt/socks/userpass.db" #ifndef CONFIG_FILE /* The default config file. */ #define CONFIG_FILE "/etc/opt/socks/sockd.conf" #endif hpsockd-0.17build2/src/sockd/signal.c0000644000000000000000000004144611024757214014413 0ustar #include "sockd.h" #ifdef __hpux #include #endif #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/signal.c,v 0.32 2002/01/10 04:37:20 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ sigset_t pendingSignals; volatile int pendingSig=0; volatile int pendingTerm; static char *makeMask(register long mask) { static char buf[20]; register int i; if ((((mask&mask-1)^mask)-1|mask) == 0xffffffff) { for (i=0;mask;mask&=mask-1,i++ ); sprintf(buf,"%d",i); return buf; } else { return inetNtoa(mask); } } static char *relopToStr(relopType op) { switch(op) { case r_eq: return ""; case r_ne: return "!"; case r_lt: return "<"; case r_le: return "<="; case r_gt: return ">"; case r_ge: return ">="; default: return "bad_op"; } } static char *hostToStr(hostType *host) { static char result[sizeof("255.255.255.255")*2+8]; if (host->mask==-1) { snprintf(result,sizeof(result),"%s%s",relopToStr(host->op),inetNtoa(host->value)); } else if (host->mask) { snprintf(result,sizeof(result),"%s%s/%s",relopToStr(host->op),inetNtor(host->value), makeMask(host->mask)); } else { snprintf(result,sizeof(result),"default"); } return result; } /********************************************************************* * * Dump information on every client we have (request and totals to * date). This is the result of a signal. * *********************************************************************/ /* ARGSUSED */ void dumpClients(int sig) { register int fd; register char *base=config.log.dumpPrefix; register char *name; register int i; register fdInfoType *info; now=time((time_t*)NULL); /* used in makeLogRec, make it current */ if (!base) { syslog(LOG_ERR,"No dump file."); return; } name=malloc(strlen(base)+30); if (name==NULL) { freeSomeMemory(NULL); name=malloc(strlen(base)+30); } if (name==NULL) { syslog(LOG_ERR,"Out of memory in dumpClients"); return; } sprintf(name,"%s.client.%d",base,negotInfo->pid); unlink(name); fd=open(name,O_WRONLY|O_CREAT|O_EXCL,0600); if (fd<0) { syslog(LOG_ERR,"Couldn't open %s for write",name); free(name); return; } for (i=lowFd,info=fdInfo+lowFd; i<=highFd; i++,info++) { if ((info->flags&FD_IS_CLIENT) && !(info->flags&FD_IS_UDP) && info->fd>=0) { register int ret; register logRecType *rec; rec=makeLogRec(info,0); if (rec) do { ret=write(fd,rec,ntohs(rec->head.size)); } while (ret<0 && errno==EINTR); } } close(fd); free(name); if (debug&DBG_SANITY) dumpFootprint(-1); } /****************************************************************** * * dumpConfig() writes out the config file in a format that is * parseable, should the user decide to use that file next time. * Accordingly, it's rather long... * ******************************************************************/ /* ARGSUSED */ void dumpConfig(int sig) { register int fd; register FILE *f; register char *base=config.log.dumpPrefix; register char *name; time_t curTime; register int i; if (!base) { syslog(LOG_ERR,"No dump file."); return; } name=malloc(strlen(base)+30); if (name==NULL) { freeSomeMemory(NULL); name=malloc(strlen(base)+30); } if (name==NULL) { syslog(LOG_ERR,"Out of memory in dumpConfig()"); return; } sprintf(name,"%s.conf.%d",base,negotInfo->pid); unlink(name); fd=open(name,O_WRONLY|O_CREAT|O_EXCL,0600); if (fd<0) { syslog(LOG_ERR,"Couldn't open %s for write",name); free(name); return; } free(name); f=fdopen(fd,"w"); curTime=time((time_t*)NULL); fprintf(f,"# dumped on %s\n\n",ctime(&curTime)); fprintf(f,"daemon {\n"); fprintf(f,"\tname\t\t\"%s\";\n",config.daemon.name); fprintf(f,"\tdirectory\t\"%s\";\n",config.daemon.directory); fprintf(f,"\tumask\t\t0o%03o;\n",config.daemon.umask); if (config.daemon.listenAddr.num) { register int j; fprintf(f,"\tlisten-address\t{ "); for (j=0;j60000 # milli-per-client 0 avg %d\n", avgClientTime); } if (config.daemon.flags) { fprintf(f,"\tflags\t\t{ "); if (config.daemon.flags&FL_V4_ONLY) fprintf(f,"v4-only; "); fprintf(f,"};\n"); } fprintf(f,"};\n\n"); if (config.env.num) { fprintf(f,"env {\n"); for (i=0;iname); } fprintf(f,"};\n\t};\n"); } fprintf(f,"};\n\n"); fprintf(f,"client {\n"); for (i=0;ipid; if (!base) { syslog(LOG_ERR,"No dump file."); return; } if (fork()) return; name=malloc(strlen(base)+30); if (name) { sprintf(name,"%s.memmap.%d",base,pid); } else { syslog(LOG_ERR,"Out of memory in dumpMap() - using %s for filename",base); name=base; } unlink(name); fd=open(name,O_WRONLY|O_CREAT|O_EXCL,0600); if (fd<0) { syslog(LOG_ERR,"Couldn't open %s for write",name); return; } fflush(stdout); dup2(fd,1); dup2(fd,2); time(&timeVal); printf("%s\n", ctime(&timeVal)); _memorymap(1); printf("End of dump\n"); U_STACK_TRACE(); abort(); } #endif /********************************************************************* * * End it all. Close every connection, and then destroy the daemon. * (clean everything up and exit.) * *********************************************************************/ void terminate(int sig) { register int i; register fdInfoType *info; syslog(LOG_WARNING,"terminating on signal %d",sig); for (i=lowFd,info=fdInfo+lowFd; i<=highFd; i++,info++) { if (info->fd>=0 && (info->flags&FD_IS_CLIENT)) closeConnection(info,LOG_SIGNAL+sig,1); } destroyDaemon(); } void dnsTerminate(int sig) { syslog(LOG_WARNING,"dns helper terminating on signal %d",sig); exit(0); } /********************************************************************* * * Setup all signals for the deamon. We catch just about everything * that we can, and ignore most of them. The ones we do catch just * set a flag in pendingSignals, so that mainLoop() can schedule them * at a safe and reasonable time. * *********************************************************************/ typedef void (sigactFunc)(int); void setupSignals(int daemon) { register int ret,i; struct sigaction act; memset(&act,0,sizeof(act)); sigfillset(&act.sa_mask); sigdelset(&act.sa_mask,SIGTRAP); act.sa_handler=SIG_IGN; /* first, just ignore everything */ for (i=1;isc_syscall==SYS_select) { scp->sc_syscall_action=SIG_RETURN; } #endif } /********************************************************************* * * For each signal we care about, if we got one, call the handler. * At some point, we may have enough to make a switch statement make * sense. Order counts here: if they send two of one signal, we're * allowed to only do it once, but we're not allowed to loose track * of any: check it, clear it, and call the handler. * *********************************************************************/ void doSignals(void) { pendingSig=0; /* if we're not going to call them all, then remember to do it later. */ /* XXX - probably should block signals, since there is a small window in sigdelset where we could lose one */ #define callit(sig,handler) { if (sigismember(&pendingSignals,(sig))) \ { footprint(7,(sig),0,0); \ sigdelset(&pendingSignals,(sig)); \ handler ((sig)); } } #ifdef __hpux callit(SIGSYS,dumpMap) #endif callit(SIGUSR1,dumpClients) callit(SIGUSR2,dumpConfig) /* in gram.y */ callit(SIGHUP,readConfig) /* in sockd.c */ callit(SIGINT,newLog) /* in logging.c */ callit(SIGEMT,unListen) /* in listen.c */ callit(SIGTERM,terminate) #undef callit } hpsockd-0.17build2/src/sockd/userpass.c0000644000000000000000000000714611024757214015002 0ustar #include "sockd.h" #include "v5.h" #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/userpass.c,v 0.16 2001/05/14 14:31:21 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define USERPASS_VERSION 1 inboundFunc v5UserPassNegotiate; static DB *userDB=NULL; int userPassInfo(methodInfoType *info,int version) { if (version!=METHOD_VERSION) return -1; info->negotiate=v5UserPassNegotiate; #if FULLMETHOD info->TCP_INBOUND=simpleInbound; info->TCP_OUTPUT=simpleOutput; #endif return 0; } /************************************************************* * +----+------+----------+------+----------+ * |VER | ULEN | UNAME | PLEN | PASSWD | * +----+------+----------+------+----------+ * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | * +----+------+----------+------+----------+ *************************************************************/ int v5UserPassInit(fdInfoType *client, unsigned int flags) { register const char *name=getEnv(client,"USERPASSDB_PATH"); if (!name) name=USERPASSDB_PATH; userDB=dbopen(name,O_RDONLY,0600,DB_HASH,NULL); if (!userDB) { syslog(LOG_ERR,"userpass: Unable to open database %s: %m",name); return -1; } return 0; } int v5UserPassAuth(fdInfoType *client, char *user,const char *pass, unsigned int flags) { int ret=SOCKS5_DENIED; DBT key,data; register int dbRes; key.data = user; key.size = strlen(user); dbRes=userDB->get(userDB,&key,&data,0); if(dbRes<0) { syslog(LOG_ERR,"userpass: db error on get: %m"); } else if (dbRes>0) { syslog(LOG_WARNING,"userpass: %s not known",user); } else if (data.size==strlen(pass) && memcmp(data.data,pass,data.size)==0) { ret=0; } else { syslog(LOG_WARNING,"userpass: Bad password for user %s",user); } return ret; } /* inboundFunc */ /* ARGSUSED */ void v5UserPassNegotiate(fdInfoType *client,void *buf,int len,unsigned int flags) { register int l; register int present; register char *user; register char *pass; register int ret=SOCKS5_DENIED; u_char req[256+256+4]; u_char reply[2]; addToBuffer(client,&client->in,buf,len); if (!userDB) { v5UserPassInit(client, flags); } present=client->in.dataLen; if (present<3 || present<(l=3+client->in.dataStart[1]) || present<(l=l+client->in.dataStart[l-1])) return; client->TCP_INBOUND=simpleInbound; getFromBuffer(&req,&client->in,l,0); req[l]='\0'; user=(char*)req+2; pass=user+user[-1]+1; pass[pass[-1]]='\0'; pass[-1]='\0'; client->conn->user=strdup(user); if (*req==USERPASS_VERSION) { ret=v5UserPassAuth(client,user,pass,flags); } Bailout: reply[0]=USERPASS_VERSION; reply[1]=ret; client->TCP_OUTPUT(client,(void*)&reply,sizeof(reply),0); if (ret) { pendingClose(client,ret); } } hpsockd-0.17build2/src/sockd/gram.y0000644000000000000000000006120311024757214014103 0ustar %{ #include "sockd.h" #include #include #include #include #define YYDEBUG 1 void dumpTokens(void); #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/gram.y,v 0.51 2002/01/08 08:13:18 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ configInfoType newConfig; static int cleanupConfig(void); methodInfoType *findMethod(configInfoType *cfg,char *name); static clientInfoType clInfo; static methodInfoType methElem; static clientMethodInfoType clientMethElem; static hostLType makeHostSpec(relopType op, long mask, longLType list); static int goodEq, goodSrc; /* found a good equal compare in src statement for a client */ #define NEWLIST(l,i) { (l).list=malloc(sizeof(i)), (l).num=1; \ if ((l).list==NULL) { syslog(LOG_ERR,"Out of memory in parser"); YYABORT; } \ (l).list[0]=(i); } #define ADDTOLIST(l,i) { (l).list=realloc((l).list,++(l).num*sizeof(i)); \ if ((l).list==NULL) { syslog(LOG_ERR,"Out of memory in parser"); YYABORT; } \ (l).list[(l).num-1]=(i); } #define APPENDTOLIST(l,m) { (l).list=realloc((l).list,((l).num+(m).num)*sizeof(*(m).list)); \ if ((l).list==NULL) { syslog(LOG_ERR,"Out of memory in parser"); YYABORT; } \ memcpy((l).list+((l).num),(m).list,(m).num*sizeof(*(m).list)); (l).num += (m).num; \ free((m).list); (m).list=NULL; } #ifdef __hpux #define DEFAULT_GID -2 #else #define DEFAULT_GID 65534 #endif %} %union { int iVal; char *sVal; strLType uStr; hostLType hStr; longLType iStr; portLType pStr; portType pVal; hostType hVal; relopType opVal; clientInfoType clInf; clInLType clStr; routeInfoType rInf; rtInLType rStr; methodInfoType mInf; mInfLType mStr; clientMethodInfoType cmInf; cmInLType cmStr; methodInfoType *mPtr; mInPLType mPStr; struct { int num1, num2; } nPair; } %type hostaddr %type rangeaddr %type ifaddr %type hostToken %type hostaddrs %type users %type port %type portNum %type portlist %type hostSpec %type hostlist %type clientInfo %type clients %type routeElem %type routeInfo %type method_elem %type methods %type cliMethElem %type cliMeths %type methList %type methodElem %type numPair %type numSemi %type strSemi %type strOrNone %type compStrOrNone %type envList %type env %type envSemi %type relop %token T_BADTOKEN %token T_DAEMON %token T_LISTENADDR %token T_SERVICE %token T_USER %token T_GROUP %token T_PREFORK %token T_NUMHELPER %token T_LISTEN %token T_CLIENT %token T_CLIENT_PER_MIN %token T_NAME %token T_DIRECTORY %token T_UMASK %token T_NEGOTFILE %token T_INETDSEC %token T_NONE %token T_POLL %token T_ENV %token T_FLAGS %token T_LOGGING %token T_LEVEL %token T_FACIL %token T_DUMPPREFIX %token T_LOGFILE %token T_DEBUG %token T_DEFAULT %token T_TIMEOUT %token T_SETUPTIMEOUT %token T_BUFSIZE %token T_ROUTE %token T_HOST %token T_METHOD %token T_METHODLIST %token T_LIB %token T_NUMBER %token T_CLIENTMETH %token I_ACTION %token I_REQ %token T_SRC %token T_DEST %token T_PORT %token T_CMD %token T_INTERNAL %token S_STR /* strdup() */ %token S_COMPLEXSTR /* strdup() */ %token S_ENV /* strdup() */ %token I_IP4 %token I_IPPREFIX %token I_NUM %token I_TIME %token I_FLAG %type timeOrNumSemi %token E_RELOP %token START /* { */ %start config /* { */ %% config: { defaultConfig(); } conf { if (cleanupConfig()==0) YYACCEPT; else YYABORT;} ; conf: cfent | conf cfent ; cfent: T_DAEMON START dI End | env { newConfig.env=$1; } | T_LOGGING START logI End | T_DEFAULT START defI End | T_ROUTE START routeInfo End { newConfig.routes=$3; } | T_CLIENT START clients End { newConfig.clients=$3; } | T_METHODLIST START methods End { newConfig.methods=$3; } | T_CLIENTMETH START cliMeths End { newConfig.cliMeth=$3; } ; dI: /* make it recurse */ | dI T_LISTENADDR START hostaddrs End { newConfig.daemon.listenAddr=$4; } | dI T_SERVICE strSemi { struct servent *sp=getservbyname($3,"tcp"); if (!sp) { syslog(LOG_ERR,"No such service %s",$3); YYABORT; } if (newConfig.daemon.service) free(newConfig.daemon.service); newConfig.daemon.service=$3; if (newConfig.daemon.port == -1) newConfig.daemon.port=sp->s_port; } | dI T_PORT numSemi { if (!newConfig.daemon.service) { register struct servent *sp=getservbyport(htons($3),"tcp"); if (!sp) { syslog(LOG_WARNING,"No service on %d, using 'socks'",$3); newConfig.daemon.service=strdup("socks"); } else { newConfig.daemon.service=strdup(sp->s_name); } } newConfig.daemon.port=htons($3); } | dI T_NAME strSemi { newConfig.daemon.name=$3; } | dI T_DIRECTORY strSemi { newConfig.daemon.directory=$3; } | dI T_UMASK numSemi { newConfig.daemon.umask=$3; } | dI T_NEGOTFILE strSemi { newConfig.daemon.negotFile=$3; } | dI T_PREFORK numSemi { newConfig.daemon.preFork=$3; } | dI T_NUMHELPER numSemi { newConfig.daemon.numHelper=$3; } | dI T_LISTEN numPair { if ($3.num1 < 1) { syslog(LOG_WARNING,"Number of listeners set to 1"); $3.num1=1; } newConfig.daemon.minListen=$3.num1; if ($3.num2 > NEGOT_MAXSLOT) { $3.num2=NEGOT_MAXSLOT; syslog(LOG_WARNING,"Listners limited to %d\n",$3.num2); } newConfig.daemon.maxListen=$3.num2; } | dI T_CLIENT numPair { newConfig.daemon.minClient=$3.num1; newConfig.daemon.maxClient=$3.num2; } | dI T_CLIENT_PER_MIN numSemi { newConfig.daemon.milliPerClient=60000/$3; } | dI T_USER userInfo | dI T_GROUP groupInfo | dI T_INETDSEC strOrNone { newConfig.daemon.inetdSecFile=$3; } | dI T_POLL timeOrNumSemi { newConfig.daemon.poll=$3; } | dI T_FLAGS START dF End dF: /* make it recursive */ | dF I_FLAG ';' { newConfig.daemon.flags|=$2; } ; env: T_ENV START envList End { $$=$3; } ; envList: envSemi { NEWLIST($$,$1); } | envList envSemi { ADDTOLIST($$,$2); } ; numPair: START I_NUM ',' I_NUM End { $$.num1=$2; $$.num2=$4; } ; userInfo: strSemi { struct passwd *pw=getpwnam($1); if (!pw) { syslog(LOG_ERR,"No such user %s",$1); YYABORT; } newConfig.daemon.uid=pw->pw_uid; if (newConfig.daemon.gid == DEFAULT_GID ) newConfig.daemon.gid=pw->pw_gid; free($1); } | numSemi { newConfig.daemon.uid=$1; } ; groupInfo: strSemi { struct group *gr=getgrnam($1); if (!gr) { syslog(LOG_ERR,"No such group %s",$1); YYABORT; } newConfig.daemon.gid=gr->gr_gid; free($1); } | numSemi { newConfig.daemon.gid=$1; } ; logI: /* make it recurse */ | logI T_FACIL strSemi { newConfig.log.facility=strToFacility($3); free($3); } | logI T_LEVEL numSemi { newConfig.log.level=$3; } | logI T_LOGFILE strOrNone { newConfig.log.logFile=$3; } | logI T_DUMPPREFIX strOrNone { newConfig.log.dumpPrefix=$3; } | logI T_DEBUG numSemi { debug=$3; } ; defI: /* make it recurse */ | defI T_TIMEOUT timeOrNumSemi { newConfig.defaults.timeOut=$3; } | defI T_SETUPTIMEOUT timeOrNumSemi { newConfig.defaults.setupTimeOut=$3; } | defI T_BUFSIZE numSemi { newConfig.defaults.bufSize=$3; } ; timeOrNumSemi: numSemi | I_TIME ';' ; routeInfo: routeElem | routeInfo routeElem { APPENDTOLIST($$,$2); } ; routeElem: START hostSpec ifaddr End { routeInfoType t; register int i; t.ip=$3.list[0]; if ($3.num>1) syslog(LOG_WARNING, "More than one address for interface, using %s", inetNtoa(t.ip)); t.host=$2.list[0]; NEWLIST($$,t); for (i=1;i<$2.num; i++) { t.host=$2.list[i]; ADDTOLIST($$,t); } free($2.list); free($3.list); } ; clients: clientInfo { NEWLIST($$,$1); } | clients clientInfo { ADDTOLIST($$,$2); } ; clientInfo: I_ACTION { memset(&clInfo,0,sizeof(clInfo)); clInfo.action=$1; goodSrc=0; } request START cliDefs End { $$=clInfo; if (clInfo.action==ACTION_PERMIT && !goodSrc) { syslog(LOG_ERR,"Lacking good source specification on permit line"); YYABORT; } } ; request: /* optional */ | I_REQ { clInfo.request=$1; } | I_NUM { clInfo.request=$1; } ; cliDefs: /* make it recursive */ | cliDefs T_USER START users End { clInfo.users=$4; } | cliDefs T_SRC { goodEq=0; } START hostlist End { clInfo.src=$5; goodSrc=goodEq; } | cliDefs T_DEST START hostlist End { clInfo.dest=$4; } | cliDefs T_PORT START portlist End { clInfo.port=$4; } | cliDefs T_CMD compStrOrNone { clInfo.cmd=$3; } | cliDefs T_TIMEOUT timeOrNumSemi { clInfo.timeOut=$3; } | cliDefs T_BUFSIZE numSemi { clInfo.bufSize=$3; } | cliDefs T_FLAGS numSemi { clInfo.flags|=$3; } ; users: strSemi { NEWLIST($$,$1); } | users strSemi { ADDTOLIST($$,$2); } ; hostlist: hostSpec ';' { goodEq+=($1.list->op==r_eq && $1.list->mask); $$=$1; } | hostlist hostSpec ';' { goodEq+=($2.list->op==r_eq && $2.list->mask); APPENDTOLIST($$,$2); } ; hostSpec: relop hostaddr { $$=makeHostSpec($1,-1,$2); if (!$$.list) YYABORT; } | relop rangeaddr '/' I_IP4 { $$=makeHostSpec($1,$4,$2); if (!$$.list) YYABORT; } | relop rangeaddr '/' I_NUM { $$=makeHostSpec($1,$4?htonl(-(1<<(32-$4))):0,$2); if (!$$.list) YYABORT; } | T_DEFAULT { hostType t; t.op=r_eq; t.mask=t.value=0; NEWLIST($$,t);} ; relop: { $$= r_eq; } | E_RELOP ; hostaddrs: ifaddr ';' | hostaddrs ifaddr ';' { APPENDTOLIST($$,$2); } ; ifaddr: I_IP4 { NEWLIST($$,$1); } | hostToken | S_STR { struct ifreq ifr; register int localFd=socket(AF_INET,SOCK_DGRAM,0); strncpy(ifr.ifr_name,$1,sizeof(ifr.ifr_name)); if (ioctl(localFd,SIOCGIFADDR,&ifr)==0) { NEWLIST($$,((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr.s_addr); } else { struct hostent *hp; register int i; if ((hp=gethostbyname($1))==NULL) { syslog(LOG_ERR,"No such interface or host"); YYABORT; } NEWLIST($$,*(int*)hp->h_addr_list[0]); for (i=1; hp->h_addr_list[i]; i++) ADDTOLIST($$,*(int*)hp->h_addr_list[i]); } free($1); close(localFd); } ; rangeaddr: hostaddr { $$=$1; } | I_NUM { NEWLIST($$,htonl($1<<24)); } | I_IPPREFIX { NEWLIST($$,$1); } ; hostaddr: I_IP4 { NEWLIST($$,$1); } | hostToken { $$=$1; } | S_STR { struct hostent *hp; register int i; if ((hp=gethostbyname($1))==NULL) { syslog(LOG_ERR,"No such host"); YYABORT; } NEWLIST($$,*(int*)hp->h_addr_list[0]); for (i=1; hp->h_addr_list[i]; i++) ADDTOLIST($$,*(int*)hp->h_addr_list[i]); free($1); } ; hostToken: T_HOST { struct hostent *hp; char tmp[MAXPATHLEN]; register int i; gethostname(tmp,sizeof(tmp)); if ((hp=gethostbyname(tmp))==NULL) { syslog(LOG_ERR,"No such host"); YYABORT; } NEWLIST($$,*(int*)hp->h_addr_list[0]); for (i=1; hp->h_addr_list[i]; i++) ADDTOLIST($$,*(int*)hp->h_addr_list[i]); } ; portlist: port ';' { NEWLIST($$,$1); } | portlist port ';' { ADDTOLIST($$,$2); } ; port: portNum { $$.low=$1, $$.high=$1; } | portNum '-' portNum { $$.low=$1, $$.high=$3; } ; portNum: I_NUM { $$ = htons($1); } | S_STR { struct servent *sp=getservbyname($1,"tcp"); if (!sp) { syslog(LOG_ERR,"No such service %s",$1); YYABORT; } $$=sp->s_port; free($1); } ; methods: method_elem { NEWLIST($$,$1); } | methods method_elem { ADDTOLIST($$,$2); } ; method_elem: START { memset(&methElem,0,sizeof(methElem)); } methodComps End { $$=methElem; if (loadMethInfo(&$$)) { syslog(LOG_ERR,"Failed to load method %s\n",$$.name); YYABORT; } } ; methodComps: /* make it recursable */ | methodComps T_NAME strSemi { methElem.name=$3; } | methodComps T_LIB strSemi { methElem.libName=$3; } | methodComps T_INTERNAL ';' { methElem.libName=NULL; } | methodComps T_NUMBER numSemi { if ($3<0 || $3>254) { syslog(LOG_ERR,"Bad method number %d",$3); YYABORT; } else { methElem.num=$3; } } | methodComps T_FLAGS numSemi { methElem.flags=$3; } | methodComps env { methElem.env=$2; } ; cliMeths: cliMethElem { NEWLIST($$,$1); } | cliMeths cliMethElem { ADDTOLIST($$,$2); } ; cliMethElem: START { memset(&clientMethElem,0,sizeof(clientMethElem)); } cMComps End { $$=clientMethElem; } ; cMComps: /* make it recursable */ | cMComps T_SRC START hostlist End { clientMethElem.src=$4; } | cMComps T_METHOD START methList End { clientMethElem.methods=$4; } ; methList: methodElem { NEWLIST($$,$1); } | methList methodElem { ADDTOLIST($$,$2); } ; methodElem: strSemi { if (($$=findMethod(&newConfig,$1))==NULL) { YYABORT; } free($1); } ; numSemi: I_NUM ';' ; envSemi: S_ENV ';' ; strSemi: S_STR ';' ; compStrOrNone: strOrNone | S_COMPLEXSTR ';' ; strOrNone: strSemi | T_NONE ';' { $$=NULL; } ; End: '}' ';' | ';' '}' ';' /* Allow an extra semicolon before the brace. */ ; %% /* } */ /****************************************************************** * * defaultConfig() and cleanupConfig() conspire to fill in any * default values not specified in the config file. defaultConfig() * is called at the start of things, and cleanupConfig() is called * just before yyparse() returns. Accordingly, defaultConfig() * initializes all of the non-string values (after zeroing the * entire structure, and cleanupConfig sets any string values that * need to be, along with doing sanity checks, and possibly causing * the parsing of the config file to fail. * ******************************************************************/ void defaultConfig(void) { memset(&newConfig,0,sizeof(newConfig)); newConfig.daemon.uid=-2; newConfig.daemon.gid=DEFAULT_GID; newConfig.daemon.port=-1; /* This will change if not specified */ newConfig.daemon.minListen=1; newConfig.daemon.maxListen=NEGOT_MAXSLOT; newConfig.daemon.minClient=1; newConfig.daemon.maxClient=200; newConfig.daemon.poll=60; /* one minute */ newConfig.daemon.numHelper=1; newConfig.daemon.umask=002; newConfig.log.level=LG_STATS; newConfig.log.facility=LOG_DAEMON; newConfig.defaults.bufSize=32768; newConfig.defaults.timeOut=2*60*60; /* default timeout */ newConfig.defaults.setupTimeOut=15*60; newConfig.routes.num=0; newConfig.clients.num=0; } static int cleanupConfig(void) { register int ret=0; if (!newConfig.routes.num) { syslog(LOG_ERR,"No routes in config file."); ret=1; } if (!newConfig.clients.num) { syslog(LOG_ERR,"No clients in config file."); ret=1; } if (!newConfig.daemon.name) newConfig.daemon.name=strdup("sockd"); if (!newConfig.daemon.directory) newConfig.daemon.directory=strdup("/var/opt/socks"); if (!newConfig.daemon.negotFile) { syslog(LOG_ERR,"No negotiate-file specified."); ret=1; } if (!newConfig.daemon.service) { struct servent *sp=getservbyname("socks","tcp"); newConfig.daemon.service=strdup("socks"); if (!sp) { syslog(LOG_WARNING,"No such service socks, using 1080"); newConfig.daemon.port=htons(1080); } else { newConfig.daemon.port=sp->s_port; } } if (newConfig.daemon.preFork > newConfig.daemon.maxListen) { syslog(LOG_WARNING,"Stupid pre-fork %d, chopping to %d", newConfig.daemon.preFork, newConfig.daemon.maxListen); newConfig.daemon.preFork = newConfig.daemon.maxListen; } if (!newConfig.log.logFile && newConfig.log.level) { syslog(LOG_WARNING,"No log file given, log level set to 0"); newConfig.log.level=0; } if (newConfig.daemon.flags&FL_V4_ONLY) newConfig.daemon.numHelper=0; return ret; } /****************************************************************** * * freeConfig() is responsible for making sure that rereading the * config file does not result in memory leaking out onto the * floor. If there was anything malloc'ed (or strdup'ed) during * reading the config file, then we free it here. * ******************************************************************/ void freeConfig(configInfoType *cfg) { register int i; free(cfg->daemon.listenAddr.list); free(cfg->daemon.name); free(cfg->daemon.directory); free(cfg->daemon.service); free(cfg->daemon.negotFile); if (cfg->daemon.inetdSecFile) free(cfg->daemon.inetdSecFile); if (cfg->log.logFile) free(cfg->log.logFile); if (cfg->log.dumpPrefix) free(cfg->log.dumpPrefix); if (cfg->routes.num) { free(cfg->routes.list); cfg->routes.list=NULL; cfg->routes.num=0; } if (cfg->env.num) { register int j; for (j=cfg->env.num-1;j>=0;j--) free(cfg->env.list[j]); free(cfg->env.list); cfg->env.list=NULL; } if (cfg->methods.num) { #if 0 /* we have to leak the method data, since there may be references * to it from fdInfo[]... One small leak per config file reload. */ for (i=cfg->methods.num-1;i>=0;i--) { free(cfg->methods[i].name); if (cfg->methods[i].libName) free(cfg->methods[i].libName); cfg->methods[i].name=cfg->methods[i].libName=NULL; if (cfg->methods[i].env.num) { register int j; for (j=cfg->methods[i].env.num-1;j>=0;j--) free(cfg->methods[i].env.list[j]); free(cfg->methods[i].env.list); cfg->methods[i].env.list=NULL; } } free(cfg->methods.list); #endif cfg->methods.list=NULL; } if (cfg->cliMeth.num) { for(i=cfg->cliMeth.num-1;i>=0;i--) { register int j; free(cfg->cliMeth.list[i].src.list); cfg->cliMeth.list[i].src.list=NULL; if (cfg->cliMeth.list[i].methods.num) { free(cfg->cliMeth.list[i].methods.list); cfg->cliMeth.list[i].methods.list=NULL; } } free(cfg->cliMeth.list); cfg->cliMeth.list=NULL; } if (cfg->clients.num) { for (i=cfg->clients.num-1;i>=0;i--) { register int j; if (cfg->clients.list[i].users.num) { for (j=cfg->clients.list[i].users.num-1;j>=0;j--) free(cfg->clients.list[i].users.list[j]); free(cfg->clients.list[i].users.list); cfg->clients.list[i].users.list=NULL; } if (cfg->clients.list[i].src.num) { free(cfg->clients.list[i].src.list); cfg->clients.list[i].src.list=NULL; } if (cfg->clients.list[i].dest.num) { free(cfg->clients.list[i].dest.list); cfg->clients.list[i].dest.list=NULL; } if (cfg->clients.list[i].port.num) { free(cfg->clients.list[i].port.list); cfg->clients.list[i].port.list=NULL; } if (cfg->clients.list[i].cmd) free(cfg->clients.list[i].cmd); } free(cfg->clients.list); cfg->clients.list=NULL; cfg->clients.num=0; } } /****************************************************************** * * strToFacility() takes the user specified name and turns it into * something that we can use. facilityToStr() reverses the process. * ******************************************************************/ int strToFacility(char *name) { if (strcmp(name,"daemon")==0) { return LOG_DAEMON; } else if (strcmp(name,"local0")==0) { return LOG_LOCAL0; } else if (strcmp(name,"local1")==0) { return LOG_LOCAL1; } else if (strcmp(name,"local2")==0) { return LOG_LOCAL2; } else if (strcmp(name,"local3")==0) { return LOG_LOCAL3; } else if (strcmp(name,"local4")==0) { return LOG_LOCAL4; } else if (strcmp(name,"local5")==0) { return LOG_LOCAL5; } else if (strcmp(name,"local6")==0) { return LOG_LOCAL6; } else if (strcmp(name,"local7")==0) { return LOG_LOCAL7; } else if (strcmp(name,"kern")==0) { return LOG_KERN; } else if (strcmp(name,"user")==0) { return LOG_USER; } else if (strcmp(name,"mail")==0) { return LOG_MAIL; } else if (strcmp(name,"auth")==0) { return LOG_AUTH; } else if (strcmp(name,"syslog")==0) { return LOG_SYSLOG; } else if (strcmp(name,"lpr")==0) { return LOG_LPR; } else { syslog(LOG_WARNING,"Unknown facility %s, using daemon",name); return LOG_DAEMON; } } char* facilityToStr(int facil) { if (facil==LOG_DAEMON) { return "daemon"; } else if (facil==LOG_LOCAL0) { return "local0"; } else if (facil==LOG_LOCAL1) { return "local1"; } else if (facil==LOG_LOCAL2) { return "local2"; } else if (facil==LOG_LOCAL3) { return "local3"; } else if (facil==LOG_LOCAL4) { return "local4"; } else if (facil==LOG_LOCAL5) { return "local5"; } else if (facil==LOG_LOCAL6) { return "local6"; } else if (facil==LOG_LOCAL7) { return "local7"; } else if (facil==LOG_KERN) { return "kern"; } else if (facil==LOG_USER) { return "user"; } else if (facil==LOG_MAIL) { return "mail"; } else if (facil==LOG_AUTH) { return "auth"; } else if (facil==LOG_SYSLOG) { return "syslog"; } else if (facil==LOG_LPR) { return "lpr"; } else { return "unknown"; } } /****************************************************************** * * Not much of an error handler, but, hey, it's what we have. * ******************************************************************/ yyerror(char *s) { fprintf(stderr,"%s\nLast tokens were:\n",s); dumpTokens(); syslog(LOG_ERR,"%s\n",s); } /****************************************************************** * * findMethod() takes a method by name and tracks it down. * config file does not result in memory leaking out onto the * floor. If there was anything malloc'ed (or strdup'ed) during * reading the config file, then we free it here. * ******************************************************************/ methodInfoType *findMethod(configInfoType *cfg,char *name) { methodInfoType *m=cfg->methods.list; register int i=cfg->methods.num; for (;i>0;i--,m++) { if (strcmp(name,m->name)==0) return m; } syslog(LOG_ERR,"Could not find method %s",name); return NULL; } extern int zzlex(void); #define MAX_TOKEN_HIST 30 int tokenHistory[MAX_TOKEN_HIST]; int tokenValues[MAX_TOKEN_HIST]; int tokenHistNext; int tokenHistWrapped; int yylex(void) { register int token=zzlex(); tokenValues[tokenHistNext]=yylval.iVal; tokenHistory[tokenHistNext++]=token; if (tokenHistNext>=MAX_TOKEN_HIST) { tokenHistNext=0; tokenHistWrapped=1; } return token; } void dumpTokens(void) { register int i= tokenHistWrapped ? tokenHistNext : 0; do { if (tokenHistory[i]==START) { fprintf(stderr,"{ "); } else if (tokenHistory[i]<256) { if (tokenHistory[i]=='{') fprintf(stderr,"LBRACE!!"); else putc(tokenHistory[i],stderr); } else { switch (*(yyname[tokenHistory[i]])) { case '\'': putc(yyname[tokenHistory[i]][1],stderr); break; case 'E': fprintf(stderr," enum(%u)",tokenValues[i]); break; case 'I': fprintf(stderr," %u",tokenValues[i]); break; case 'T': putc('\n',stderr); /* fall through */ default: fprintf(stderr,"%s ",yyname[tokenHistory[i]]); break; } } if (++i>=MAX_TOKEN_HIST) i=0; } while (i!=tokenHistNext); putc('\n',stderr); } static hostLType makeHostSpec(relopType op, long mask, longLType list) { hostLType ret; register hostType *p; register long *s; register int i; ret.num=list.num; ret.list=malloc(sizeof(hostType)*list.num); if (ret.list==NULL) { syslog(LOG_ERR,"Out of memory in parser"); return ret; } for (i=0,p=ret.list,s=list.list;iop=op, p->mask=mask, p->value=(*s&mask); } free(list.list); return ret; } hpsockd-0.17build2/src/sockd/lexer.l0000644000000000000000000002145711024757214014266 0ustar hex 0x([A-Fa-f0-9])+ dec ([1-9][0-9]*|0) oct 0o([0-7])+ num ({hex}|{dec}|{oct}) ip4 ({num}\.){3}{num} ipprefix ({num}\.){1,2}{num} %{ #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/lexer.l,v 0.34 2002/01/10 18:54:45 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sockd.h" #include "gram.tab.h" #define yylex zzlex static char * dequoteEnv(char *s); int getSpecial(char **str); int tonum(char *s,int len,int base); %} %option noyywrap /* No is for rules that are turned off right now. We may turn them on later... */ %x Str No %% [ \t\n]+ ; \#.*\n ; daemon { return T_DAEMON; } directory { return T_DIRECTORY; } umask { return T_UMASK; } service { return T_SERVICE; } listen-address { return T_LISTENADDR; } listen-addr { return T_LISTENADDR; } user { return T_USER; } group { return T_GROUP; } pre-fork { return T_PREFORK; } dns-helper { return T_NUMHELPER; } listen { return T_LISTEN; } client { return T_CLIENT; } name { return T_NAME; } negotiate-file { return T_NEGOTFILE; } inetdsec-file { return T_INETDSEC; } none { return T_NONE; } poll { return T_POLL; } env { return T_ENV; } clients-per-min { return T_CLIENT_PER_MIN; } flags { return T_FLAGS; } v4-only { yylval.iVal=FL_V4_ONLY; return I_FLAG; } no-keepalive { yylval.iVal=FL_NO_KEEPALIVE; return I_FLAG; } logging { return T_LOGGING; } level { return T_LEVEL; } facility { return T_FACIL; } usage-log { return T_LOGFILE; } dump-prefix { return T_DUMPPREFIX; } debug { return T_DEBUG; } default { return T_DEFAULT; } timeout { return T_TIMEOUT; } setup-timeout { return T_SETUPTIMEOUT; } bufsize { return T_BUFSIZE; } route { return T_ROUTE; } host { return T_HOST; } method-list { return T_METHODLIST; } library { return T_LIB; } number { return T_NUMBER; } internal { return T_INTERNAL; } client-method { return T_CLIENTMETH; } method { return T_METHOD; } permit { yylval.iVal=ACTION_PERMIT; return I_ACTION; } permit! { yylval.iVal=ACTION_PERMIT_OK; return I_ACTION; } deny { yylval.iVal=ACTION_DENY; return I_ACTION; } skip { yylval.iVal=ACTION_SKIP; return I_ACTION; } connect { yylval.iVal=SOCKS5_CONNECT; return I_REQ; } bind { yylval.iVal=SOCKS5_BIND; return I_REQ; } udp-associate { yylval.iVal=SOCKS5_UDP_ASSOCIATE; return I_REQ; } ping { yylval.iVal=SOCKS5_PING; return I_REQ; } traceroute { yylval.iVal=SOCKS5_TRACEROUTE; return I_REQ; } src { return T_SRC; } dest { return T_DEST; } port { return T_PORT; } cmd { return T_CMD; } \=\=? { yylval.opVal=r_eq; return E_RELOP; }; \!\=?|\<\> { yylval.opVal=r_ne; return E_RELOP; }; \> { yylval.opVal=r_gt; return E_RELOP; }; \>\= { yylval.opVal=r_ge; return E_RELOP; }; \< { yylval.opVal=r_lt; return E_RELOP; }; \<\= { yylval.opVal=r_le; return E_RELOP; }; \{ { return START; } [-}|/;,] { return yytext[0]; } {ip4} { yylval.iVal=inetAddr(yytext); return I_IP4;} {ipprefix} { yylval.iVal=inetAddr(yytext); return I_IPPREFIX;} ({dec}[wdhms])+ { yylval.iVal=strToTime(yytext); return I_TIME; } {dec} { yylval.iVal=strtol(yytext,(char**)NULL,10); return I_NUM; } {hex} { yylval.iVal=strtol(yytext+2,(char**)NULL,16); return I_NUM; } {oct} { yylval.iVal=strtol(yytext+2,(char**)NULL,8); return I_NUM; } \"[^\"\\]*\" { register char *c=strdup(yytext+1); c[yyleng-2]='\0'; yylval.sVal=c; return S_STR; } \" { BEGIN Str; yymore(); break; } [^\\]*\\. { yymore(); break; } \n { return T_BADTOKEN; } [^\\\n]*\" { char *c; register char *d=malloc(yyleng); register int j; BEGIN INITIAL; if (!d) { syslog(LOG_WARNING,"Out of memory in lexer."); return T_BADTOKEN; } for (j=0,c=yytext+1;c.|\n { fprintf(stderr,"GOT %c\n",yytext[0]); return yytext[0]; } %% static char * dequoteEnv(char *s) { register char *c; register int i; s=strdup(s); c=strchr(s,'=')+1; memmove(c,c+1,i=(strlen(c)-2)); c[i]='\0'; return s; } int strToTime(char *in) { char *p=in; register int ret=0; register int i; while (1) { i=strtol(p,&p,10); switch(*p++) { case 'w': ret+=i*7*86400; break; /* weeks */ case 'd': ret+=i*86400; break; /* days */ case 'h': ret+=i*3600; break; /* hours */ case 'm': ret+=i*60; break; /* minutes */ case 's': ret+=i; break; /* seconds */ case '\0': return ret; } } } char *timeToStr(int time) { static char retBuf[100]; register int retLen; register int oTime=time; *retBuf='\0'; retLen=0; if (time>=7*86400) { retLen+=snprintf(retBuf+retLen,sizeof(retBuf)-retLen,"%dw",time/(7*86400)); time%=(7*86400); } if (time>=86400) { retLen+=snprintf(retBuf+retLen,sizeof(retBuf)-retLen,"%dd",time/86400); time%=86400; } if (time>=3600) { retLen+=snprintf(retBuf+retLen,sizeof(retBuf)-retLen,"%dh",time/3600); time%=3600; } if (time>=60) { retLen+=snprintf(retBuf+retLen,sizeof(retBuf)-retLen,"%dm",time/60); time%=60; } if (!oTime || time) { retLen+=snprintf(retBuf+retLen,sizeof(retBuf)-retLen,"%ds",time); } return retBuf; } int tonum(char *s,int len,int base) { int n=0; for (; len > 0; len--,s++) { n *= base; if (*s >= '0' && *s <= '9') n += (*s - '0'); else if (*s >= 'A' && *s <= 'F') n += (*s - 'A'+10); else if (*s >= 'a' && *s <= 'f') n += (*s - 'a'+10); } return(n); } int getSpecial(char **str) { char *c=*str; char d; switch(*++c) { case 'a': d='\a'; break; case 'b': d='\b'; break; case 'f': d='\f'; break; case 'n': d='\n'; break; case 'r': d='\r'; break; case 't': d='\t'; break; case 'v': d='\v'; break; case 'x': if (strchr("0123456789abcdefABCDEF",c[2]) != NULL) d=tonum((c+=2)-1,2,16); else d=tonum(++c,1,16); break; case '\'': case '\"': case '\\': case '\?': d=*c; break; default: if (*c>='0'&&*c<='7') if (c[1]>='0'&&c[1]<='7') if (c[2]>='0'&&c[2]<='7') d=tonum((c+=2)-2,3,8); else d=tonum((c+=1)-1,2,8); else d=*c-'0'; else { d='\\'; (void)fprintf(stderr,"bad \\ ignored\n"); } } *str=c; return d; } static char hexChars[16]="0123456789abcdef"; char *expandString(const char *us) { register const unsigned char *s=(const unsigned char *)us; register char *ret; register unsigned char *d; register char *str=malloc(strlen(us)*4+4); if (str==NULL) { syslog(LOG_ERR,"Out of memory in expandString()"); return strdup("??"); } d=(unsigned char *)str; for (;*s;s++) { switch (*s) { case '\a': *d++='\\', *d++='a'; break; case '\b': *d++='\\', *d++='b'; break; case '\f': *d++='\\', *d++='f'; break; case '\n': *d++='\\', *d++='n'; break; case '\r': *d++='\\', *d++='r'; break; case '\t': *d++='\\', *d++='t'; break; case '\v': *d++='\\', *d++='v'; break; case '\"': *d++='\\', *d++='\"'; break; case '\'': *d++='\\', *d++='\''; break; case '\?': *d++='\\', *d++='\?'; break; case '\\': *d++='\\', *d++='\\'; break; default: if (*s>=0x20 && *s<0x7f) { *d++=*s; } else { *d++='\\', *d++='x', *d++=hexChars[*s/16], *d++=hexChars[*s%16]; } break; } } *d++='\0'; return str; } u_int32_t inetAddr(const char *s) { register int i; const char *p; union { u_int32_t i; u_char c[4]; } v; /* this handles partial IP's (into the top of the word), while the official one is, umm, broken. */ for (v.i=0, p=s,i=0;i<4;i++,p++) { if (*p=='0' && p[1]=='x') v.c[i]=strtol(p+2,(char**)&p,16); else if (*p=='0' && p[1]=='o') v.c[i]=strtol(p+2,(char**)&p,8); else v.c[i]=strtol(p,(char**)&p,10); if (!p || !*p) break; } return v.i; } hpsockd-0.17build2/src/sockd/v5.c0000644000000000000000000002616211024757214013466 0ustar #include "sockd.h" #include "v5.h" #include #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/v5.c,v 0.49 2001/08/23 17:25:27 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ int noAuthInfo(methodInfoType *info,int version) { if (version!=METHOD_VERSION) return -1; info->negotiate=simpleInbound; #ifdef FULLMETHOD info->TCP_INBOUND=simpleInbound; info->TCP_OUTPUT=simpleOutput; #endif return 0; } /* inboundFunc */ void newV5Client(fdInfoType *client,void *buf,int len,unsigned int flags) { register methodInfoType *method; u_char reply[2]; u_char request[257]; addToBuffer(client,&client->in,buf,len); if (client->in.dataLen<2 || client->in.dataLenin.dataStart[1]+2) { return; /* still don't have enough data */ } getFromBuffer((char*)request,&client->in,client->in.dataStart[1]+2,0); method=findMatchingMethod(&client->sin,request); footprint(1,client->fd,method ? method->num : 255,client->sin.sin_addr.s_addr); reply[0]=SOCKS_V5; reply[1]=method ? method->num : 0xff; client->TCP_OUTPUT(client,(char*)&reply,2,0); if (client->fd<0) { /* TCP_OUTPUT met with resistance... */ return; } else if (!method) { pendingClose(client,LOG_NOMETHOD); return; } client->conn->method=method; /* Copy the method startup information from method into client */ client->TCP_INBOUND=method->negotiate; /* if we have data, go for it */ if (client->in.dataLen) { client->TCP_INBOUND(client,NULL,0,flags); } } /* ARGSUSED */ int v5PutSin(const struct sockaddr_in *sin, int sinLen, v5HeadType *reply) { reply->atyp=ATYP_V4; /* in case of errors */ switch (sin->sin_family) { default: reply->cmd=SOCKS5_GENFAIL; /* fall through */ case AF_INET: memcpy(reply->destAddr,&sin->sin_addr,4); memcpy(reply->destAddr+4,&sin->sin_port,sizeof(sin->sin_port)); return 4+sizeof(sin->sin_port); #ifdef AF_INET6 case AF_INET6: reply->atyp=ATYP_V6; memcpy(reply->destAddr,&sin->sin_addr,16); memcpy(reply->destAddr+16,&sin->sin_port,sizeof(sin->sin_port)); return 16+sizeof(sin->sin_port); #endif } } int v5GetSin(const v5HeadType *req,struct sockaddr_in *sin,int sinLen) { memset(sin,0,sinLen); switch (req->atyp) { case ATYP_V4: sin->sin_family=AF_INET; memcpy(&sin->sin_addr,req->destAddr,4); memcpy(&sin->sin_port,req->destAddr+4,sizeof(short)); return SOCKS5_OK; case ATYP_V6: #ifdef AF_INET6 if (sinLensin_family=AF_INET6; memcpy(&sin->sin_addr,req->destAddr,16); memcpy(&sin->sin_port,req->destAddr+16,sizeof(short)); #endif return SOCKS5_GENFAIL; case ATYP_DOMAIN: /* fall thru */ default: return SOCKS5_GENFAIL; } } /* outputFunc */ int v5Request(fdInfoType *peer,void *buf,int len,unsigned int flags) { v5HeadType req; register int ret; register fdInfoType *client=peer->peer; register connInfoType *conn=peer->conn; register int size,asize; #ifdef __lint size=flags; #endif addToBuffer(peer,&peer->out,buf,len); if (!conn->req) { /* If we got SOCKS5_TRY_AGAIN before then we already have client->req. */ if (peer->out.dataLen < sizeof(req)) return 0; memcpy(&req,peer->out.dataStart,sizeof(req)); /* see if we have enough data */ switch(req.atyp) { case ATYP_V4: asize=4; break; case ATYP_DOMAIN: asize=req.destAddr[0]+1; break; case ATYP_V6: asize=16; break; } size=sizeof(req)+sizeof(u_short)-sizeof(req.destAddr)+asize; if (peer->out.dataLen < size) return 0; conn->req=malloc(size); if (!conn->req) { freeSomeMemory(&peer->out); conn->req=malloc(size); if (!conn->req) { pendingClose(client,LOG_OUT_OF_MEMORY); return; } } getFromBuffer((char*)conn->req,&peer->out,size,0); logStartup(client); } ret=validate(client,VL_NONE,NULL); if (ret==SOCKS5_TRY_AGAIN) return 1; /* validate may have changed these. */ setupTimeouts(conn,conn->timeOut); setSocketBuffer(peer->fd,conn->bufSize); setSocketBuffer(client->fd,conn->bufSize); if (ret==SOCKS5_OK) { peer->TCP_OUTPUT=simpleOutput; /* we have the request now, don't need to come here any more */ switch(conn->req->cmd) { case SOCKS5_CONNECT: ret=v5DoConnect(client); break; case SOCKS5_BIND: ret=v5DoBind(client); break; case SOCKS5_UDP_ASSOCIATE: ret=v5DoUdpAssociate(client); break; case SOCKS5_PING: ret=v5DoCommand(client,"PING"); break; case SOCKS5_TRACEROUTE: ret=v5DoCommand(client,"TRACEROUTE"); break; default: if (conn->req->cmd<128) { syslog(LOG_ERR,"Bad v5 command %d from %s", conn->req->cmd,inet_ntoa(client->sin.sin_addr)); ret=SOCKS5_CMD_NOT_SUPP; } else { char name[16]; sprintf(name,"COMMAND_%d",conn->req->cmd); ret=v5DoCommand(client,name); } break; } } if (ret!=SOCKS5_OK) { v5HeadType reply; u_short port; memset(&reply,0,sizeof(reply)); reply.version=SOCKS_V5; reply.cmd=ret; reply.atyp=ATYP_V4; port=htons(0); v5GetSin(conn->req,&peer->sin,sizeof(peer->sin)); client->TCP_OUTPUT(client,(char*)&reply,sizeof(reply),0); client->TCP_OUTPUT(client,(char*)&port,sizeof(port),0); pendingClose(client,ret); } return 0; } int v5ErrnoToResult(int error) { switch(error) { case 0: return SOCKS5_OK; case EALREADY: case EINVAL: case ENETUNREACH: case ENETDOWN: case ENETRESET: return SOCKS5_NET_UNREACH; case EHOSTUNREACH: case EHOSTDOWN: return SOCKS5_HOST_UNREACH; case ECONNREFUSED: return SOCKS5_CONN_REFUSED; case EADDRINUSE: return SOCKS5_INVALID_ADDR; default: return SOCKS5_GENFAIL; } } void v5WriteReply(fdInfoType *client, struct sockaddr_in *sin, int result, int flags) { double dbuf[304/sizeof(double)]; v5HeadType *reply=(v5HeadType*)dbuf; register char *p=(char*)&reply->destAddr; memset(dbuf,0,sizeof(dbuf)); reply->version=SOCKS_V5; reply->cmd=result; reply->flags=flags; p+=v5PutSin(sin,sizeof(*sin),reply); client->TCP_OUTPUT(client,(char*)dbuf,(p-(char*)dbuf),0); } /*************************************************************************** * validate() verifies that the connection in question is OK. 0 means OK, * >0 is a socks return value, and you lose. ***************************************************************************/ int validate(fdInfoType *client, int flags, v5HeadType **iReq) { register connInfoType *conn=client->conn; register int i; register clientInfoType *cInfo; long destIP; u_short port; char domain[256]; struct hostent *hent; register v5HeadType *req=iReq ? *iReq : conn->req; register int cmd; register int checkDest; if (!(flags&VL_ISUDPREQ)) { if (req->version!=SOCKS_V5) return SOCKS5_GENFAIL; cmd=req->cmd; checkDest=(cmd!=SOCKS5_UDP_ASSOCIATE); } else { if (((v5UdpHeadType*)req)->rsv) return SOCKS5_GENFAIL; cmd=SOCKS5_UDP_ASSOCIATE; checkDest=1; } switch(req->atyp) { case ATYP_V4: memcpy(&destIP,req->destAddr,sizeof(destIP)); memcpy(&port,req+1,sizeof(port)); break; case ATYP_V6: return SOCKS5_ADDR_NOT_SUPP; /* XXX - no IPV6 support */ case ATYP_DOMAIN: memcpy(domain,req->destAddr+1,*req->destAddr); domain[*req->destAddr]='\0'; memcpy(&port,req->destAddr+1+*req->destAddr,sizeof(port)); if ((hent=dnsQuery(domain,client->peer))==(struct hostent*)-1) { clrSelect(client->fd,SL_READ); return SOCKS5_TRY_AGAIN; } else if (hent) { req=realloc(req,sizeof(*req)+sizeof(port)+hent->h_length-sizeof(req->destAddr)); if (!req) return SOCKS5_GENFAIL; if (!iReq) conn->req=req; else *iReq=req; switch(hent->h_addrtype) { case AF_INET: req->atyp=ATYP_V4; break; #ifdef AF_INET6 case AF_INET6: req->atyp=ATYP_V6; break; #endif default: return SOCKS5_ADDR_NOT_SUPP; } memcpy(req->destAddr,hent->h_addr_list[0],hent->h_length); memcpy(req->destAddr+hent->h_length,&port,sizeof(port)); return validate(client,flags,iReq ? iReq : NULL); /* one more time... */ } else { return SOCKS5_HOST_UNREACH; } break; } /* NEXT is used in ACTION_SKIP */ #define NEXT i--,cInfo++ for (i=config.clients.num,cInfo=config.clients.list;i>0;NEXT) { register int checks; if (cInfo->request!=SOCKS5_ANYACTION && cInfo->request != cmd) continue; checks=(cInfo->request==cmd); if (cInfo->src.num) { register hostType *sInfo; register int hit=0,j; checks++; for (sInfo=cInfo->src.list,j=cInfo->src.num; j>0; j--,sInfo++) { if (compareAddr(sInfo,client->sin.sin_addr.s_addr)) { hit=1;break; } } if (!hit) continue; } if (cInfo->dest.num && checkDest) { register hostType *dInfo; register int hit=0,j; register long dIP=destIP; checks++; for (dInfo=cInfo->dest.list,j=cInfo->dest.num; j>0; j--,dInfo++) { if (compareAddr(dInfo,dIP)) { hit=1;break; } } if (!hit) continue; } if (cInfo->port.num && checkDest) { register portType *pInfo; register int hit=0,j; register u_short p=ntohs(port); checks++; for (pInfo=cInfo->port.list,j=cInfo->port.num; j>0; j--,pInfo++) { if (p >= ntohs(pInfo->low) && p <= ntohs(pInfo->high)) { hit=1;break; } } if (!hit) continue; } if (cInfo->users.num) { register char **uInfo; register int hit=0,j; checks++; if (conn->user) { for (uInfo=cInfo->users.list,j=cInfo->users.num; j>0; j--,uInfo++) { if (strcmp(*uInfo,conn->user)==0) { hit=1;break; } } } if (!hit) continue; } if (!checkDest && !checks) continue; /* We have a winner!!! */ conn->timeOut=(cInfo->timeOut) ? cInfo->timeOut : config.defaults.timeOut; if (cInfo->bufSize) conn->bufSize=cInfo->bufSize; if (cInfo->cmd) doCommand(cInfo->cmd,client); conn->ruleFlags = cInfo->flags; if (debug&DBG_VALIDATE) { syslog(LOG_NOTICE,"validate(%d, %s:%s, %s:%d) --> %d, rule %d", cmd, inetNtoa(client->sin.sin_addr.s_addr),conn->user ? conn->user : "(NONE)", inetNtoa(destIP),port, cInfo->action,cInfo-config.clients.list); } switch (cInfo->action) { case ACTION_PERMIT: case ACTION_PERMIT_OK: return SOCKS5_OK; case ACTION_DENY: return SOCKS5_DENIED; case ACTION_SKIP: NEXT; continue; default: syslog(LOG_ERR,"Unknown action %d found, denying",cInfo->action); return SOCKS5_DENIED; } } #undef NEXT return SOCKS5_DENIED; /* not found, you lose */ } hpsockd-0.17build2/src/sockd/log2ascii.c0000644000000000000000000001343411024757214015006 0ustar #include "sockd.h" #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/log2ascii.c,v 0.16 2001/03/02 01:34:53 lamont Exp $"; static char *copyright="@(#)Copyright Hewlett-Packard Company, 1997-2000."; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ char *typeToStr(int type); int dumpAddr(char *c); int dumpString(char *c); int Read(int fd, void *ubuf, int size) { register int ret=0,r; register char *buf=ubuf; do { r=read(fd,buf,size); if (r<0) return r; else if (!r) return ret; else size-=r, buf+=r, ret+=r; } while (size); return ret; } void process_file(int fd); int sourceOnly; int follow; main(int argc,char **argv) { extern char *optarg; extern int optind; char *myname=argv[0]; register int c; while ((c=getopt(argc,argv,":fs")) != EOF) switch (c) { case 'f': follow=1; break; case 's': sourceOnly=1; break; case ':': case '?': fprintf(stderr, "Usage: %s [file...]\n", myname); exit(1); } if (follow && optind != argc-1) { fprintf(stderr,"Expected exactly one file name with -f.\n"); exit(1); } if (optind==argc) { process_file(fileno(stdin)); } else for (;optindsizeof(head)) Read(f,&rec,ntohs(head.size)-sizeof(head)); if (head.size<=sizeof(head)) continue; if (head.type >= LG_TYPE_CLIENT && head.type < LG_TYPE_CLIENT+256) { int tmp; time_t time; register int i=0; if (!sourceOnly) { memcpy(&tmp,rec.chars+i,sizeof(tmp)), i+=sizeof(tmp); printf("%u:", ntohl(tmp)); /* delta seconds*/ i+=dumpAddr(rec.chars+i); /* src */ i+=dumpString(rec.chars+i); /* user */ i+=dumpAddr(rec.chars+i); /* dest */ memcpy(&port,rec.chars+i,sizeof(port)), i+=sizeof(port); printf("%u:",ntohs(port)); /* port */ printf("%u:",rec.uchars[i++]); /* method */ memcpy(&tmp,rec.chars+i,sizeof(tmp)), i+=sizeof(tmp); printf("%u:",ntohl(tmp)); /* to src */ memcpy(&tmp,rec.chars+i,sizeof(tmp)), i+=sizeof(tmp); printf("%u:",ntohl(tmp)); /* to dest */ memcpy(&tmp,rec.chars+i,sizeof(tmp)), i+=sizeof(tmp); printf("%u\n",ntohl(tmp)); /* reason */ } else { i+=sizeof(tmp); /* point at source address */ if (rec.chars[i]==ATYP_V4) { register char *p=(char*)&tmp; memcpy(&tmp,rec.chars+i,sizeof(tmp)); if (cache[HASH(p)]==tmp) continue; cache[HASH(p)]=tmp; } (void)dumpAddr(rec.chars+i); /* XXX - assumes that reason is the last field in the record... */ memcpy(&tmp,rec.chars+head.size-sizeof(tmp)-sizeof(head),sizeof(tmp)); printf("%u\n",ntohl(tmp)); /* reason */ } } else switch(head.type) { register int i; case LG_TYPE_CONNECT: case LG_TYPE_BIND: case LG_TYPE_UDPASSOC: case LG_TYPE_PING: case LG_TYPE_TRACEROUTE: i=dumpAddr(rec.chars); i+=dumpString(rec.chars+i); i+=dumpAddr(rec.chars+i); memcpy(&port,rec.chars+i,sizeof(port)), i+=sizeof(port); printf("%d",ntohs(port)); if (i= LG_TYPE_CLIENT && type < LG_TYPE_CLIENT+256) { snprintf(buf,sizeof(buf),"Client(%s)",typeToStr(type-LG_TYPE_CLIENT)); return buf; } else switch(type) { case LG_TYPE_CONNECT: return "Cnct"; case LG_TYPE_BIND: return "Bind"; case LG_TYPE_UDPASSOC: return "Assoc"; case LG_TYPE_PING: return "Ping"; case LG_TYPE_TRACEROUTE: return "Traceroute"; case LG_TYPE_CLOSE: return "Close"; default: return "UNKNOWN"; } } int dumpAddr(char *c) { struct sockaddr_in sin; switch(*c) { case ATYP_V4: memcpy(&sin.sin_addr,c+1,4); printf("%s:",inet_ntoa(sin.sin_addr)); return 5; case ATYP_V6: printf("IPV6 address:"); return 17; case ATYP_DOMAIN: return dumpString(c+1)+1; } } int dumpString(char *c) { char name[256]; memcpy(name,c+1,*c); name[*c]='\0'; printf("%s:",name); return *c+1; } hpsockd-0.17build2/src/sockd/v4.h0000644000000000000000000000254611024757214013472 0ustar /* @(#)$Header: /var/cvs/hpsockd/src/sockd/v4.h,v 0.8 2000/12/08 20:47:24 lamont Exp $ */ /* (c) Copyright Hewlett-Packard Company 1997-2000. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef V4_H_INCLUDED #define V4_H_INCLUDED #define SOCKS_CONNECT 1 #define SOCKS_BIND 2 #define SOCKS4_RESULT 90 #define SOCKS4_FAIL 91 #define SOCKS4_NO_IDENTD 92 #define SOCKS4_BAD_ID 93 typedef struct v4Head v4HeadType; struct v4Head { u_int8_t version; /* == 4 */ u_int8_t cmd; u_int16_t port; u_int32_t destIP; char user[4]; /* actually whatever it takes... */ }; inboundFunc newV4Client; void v4DoConnect(fdInfoType *info,v4HeadType *req); void v4DoBind(fdInfoType *info,v4HeadType *req); #endif /* V4_H_INCLUDED */ hpsockd-0.17build2/src/sockd/sockd.c0000644000000000000000000004103211024757214014230 0ustar #include "sockd.h" #include #include #include extern char *socks_version; #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/sockd.c,v 0.69 2003/08/29 16:02:30 lamont Exp $"; static char *copyright="@(#)Copyright Hewlett-Packard Company, 1997-2000."; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ int main(int argc, char **argv); void mainLoop(void); void createListenSocket(void); fd_set readFds,writeFds,excpFds; volatile int highFd=0,lowFd=99999999; /* Highest/lowest fd number in use */ int maxFd; int *daemonFd; fdInfoType *fdInfo; connInfoType *connInfo; connInfoType *freeConn; negotPageType *negot; /* negotiation page */ negotInfoType *negotInfo; volatile int negotSlot; configInfoType config; int debug=DBG_SANITY; static char *configFile=CONFIG_FILE; static char syslogName[20]; time_t now; int pendingCloses; /* how many outstanding closes */ /************************************************************ * * The outerblock takes care of parsing the one or two options, * and then sets everything up. Almost everything comes from * the config file, so there aren't that many command line * options. * ************************************************************/ int main(int argc, char **argv) { register int c; register int i; struct rlimit rp; /* we want core files */ getrlimit(RLIMIT_CORE,&rp); rp.rlim_cur=0x7fffffff; rp.rlim_max=0x7fffffff; setrlimit(RLIMIT_CORE,&rp); while ((c=getopt(argc,argv,":c:d:l:vw:"))!=EOF) switch(c) { case 'c': configFile=strdup(optarg); break; case 'd': debug=strtol(optarg,(char**)NULL,0); break; case 'l': listenTries=strtol(optarg,(char**)NULL,0); break; case 'v': fprintf(stderr, "%s \n", socks_version+4); exit(0); case 'w': avgClientWeight=(float)strtol(optarg,(char**)NULL,0)/100.0; break; case ':': case '?': default: fprintf(stderr,"Usage: %s [ -c config ]\n",*argv); break; } readConfig(0); setgid(config.daemon.gid); setuid(config.daemon.uid); (void)openlog(syslogName,LOG_PID,config.log.facility); createListenSocket(); negotInit(); if (!(debug&DBG_FOREGROUND)) { register int ret=fork(); if (ret<0) { syslog(LOG_ERR,"fork: %m"); exit(1); } else if (ret) { exit(0); /* parent leaves, child does the work */ } syslog(LOG_NOTICE,"Started on port %d (%s)",ntohs(config.daemon.port),socks_version+4); freopen("/dev/null","r",stdout); freopen("/dev/null","r+",stderr); if (debug&DBG_TRAIL) freopen("debug_trail","a",stderr); setvbuf(stderr, (char *)NULL, _IONBF, 0); negot->head.processGroup=setsid(); if (negot->head.processGroup<0) { syslog(LOG_ERR,"Failed to get process group id: %m"); exit(2); } dnsGlobalInit(); /* prefork daemons */ for (i=config.daemon.preFork;i>1;i--) { register pid_t pid=fork(); if (pid==-1) { syslog(LOG_WARNING,"preFork failed: %m"); break; } else if (pid==0) { sleep(i); /* introduce some randomness */ break; } } } else { dnsGlobalInit(); } setupDaemon(0); newLog(0); gettimeofday(&lastAccept,(struct timezone*)NULL); /* make it something close... */ /* go for broke */ mainLoop(); return 1; } /************************************************************ * * This is the workhorse for the daemon. Everything that means * anything causes a file descriptor to become ready for something. * The loop takes care of calculating the next timeout, making * sure that it polls for listening every config.daemon.poll * seconds. * * For read ready descriptors, we call info->recv, and if that * returns data, we call info->inbound. Read select bits remain * on, unless the inbound func clears it. * * For write ready descriptors, we call info->send on the queued * data. If we manage to write all of the data, and there is * a peer, we turn back on his read select bit. Write select * bits are cleared if all the data is written. * * Any work scheduled by signal handlers is performed at the * top of the infinite while loop. * ************************************************************/ void mainLoop(void) { register time_t myNow; register time_t nextExpire; register time_t lastTryListen; myNow=now=time((time_t*)NULL); lastTryListen=myNow; nextExpire=myNow+config.daemon.poll; while (1) { register int fd; fd_set r,w,e; struct timeval timeout; register int num; register fdInfoType *info; register time_t *exp; register int timeouts=0; /* did something timeout (probably - the peer may save the day) */ if (pendingSig) { doSignals(); } r=readFds, w=writeFds, e=writeFds; if (nextExpirepid,num); for (fd=lowFd,info=fdInfo+lowFd;fd<=highFd;info++,fd++) { if (info->fd<0) { if (fd==lowFd) lowFd=fd; continue; } if (info->conn) { if (!FD_ISSET(fd,&e) && !FD_ISSET(fd,&w) && !FD_ISSET(fd,&r)) { if (info->conn->expire) { if (info->conn->expire<=myNow) { timeouts=1; } else if (info->conn->expireconn->expire; } } continue; } else { if (info->conn->timeOut) { info->conn->expire=myNow+info->conn->timeOut; if (info->conn->expireconn->expire; } } } if (FD_ISSET(fd,&e)) { info->excp(info); } if (FD_ISSET(fd,&w)) { register int xfr; if (info->fd<0) continue; if (debug&DBG_MAINLOOP) footprint(5,fd,info->flags,0); clrSelect(fd,SL_WRITE); if (!(info->flags&FD_IS_UDP)) { xfr=info->TCP_SEND(fd,info->out.dataStart,info->out.dataLen,0); updateTime(info,out,xfr,myNow); if (xfr>0) { info->out.dataLen-=xfr; if (!info->out.dataLen) { bufFree(&info->out); } else { info->out.dataStart+=xfr; setSelect(fd,SL_WRITE); } } else if (xfr<0) { pendingClose(info,LOG_ERRNO+errno); continue; } } if (info->peer && !info->out.dataLen) { footprint(0xb,fd,0,0); setSelect(info->peer->fd,SL_READ); } } if (FD_ISSET(fd,&r)) { register int xfr; char buf[65536]; #define TCPSIZE 1024 if (info->fd<0) continue; if (debug&DBG_MAINLOOP) footprint(0x15,fd,info->flags,0); if (!(info->flags&FD_IS_UDP)) { xfr=info->TCP_RECV(fd,buf,TCPSIZE,0); updateTime(info,in,xfr,myNow); if (xfr<0) { if (xfr==-1) pendingClose(info,LOG_ERRNO+errno); } else if (xfr) { info->TCP_INBOUND(info,buf,xfr,0); if (!info->in.dataLen) { bufFree(&info->in); } } else { pendingClose(info,LOG_CLOSE); } } else { struct sockaddr_in from; int fromLen; fromLen=sizeof(from); xfr=info->UDP_RECVFROM(fd,buf,sizeof(buf),0,&from,&fromLen); updateTime(info,in,xfr,myNow); if (xfr<0) { if (xfr==-1) pendingClose(info,LOG_ERRNO+errno); } else { info->UDP_INBOUND(info,buf,xfr,0,&from,fromLen); } } } } if (timeouts) for (fd=lowFd,info=fdInfo+lowFd;fd<=highFd;info++,fd++) { /* info->conn is set to NULL in closeConnection, so that's all we check */ if (info->conn && info->conn->expire && info->conn->expire<=myNow) { closeConnection(info,LOG_TIMEOUT,1); } } if (pendingCloses) for (fd=lowFd,info=fdInfo+lowFd;fd<=highFd;info++,fd++) { if (info->conn && (info->conn->flags&CO_CLOSE_PENDING)) { closeConnection(info,info->conn->error,info->conn->error==LOG_CLOSE ? 0 : 1); } pendingCloses=0; } } } longLType findListenInterfaces(void) { struct ifconf ifc; register struct ifreq *ifreq; struct ifreq myIfreq; char buf[32768],*cplim; register int i, fd=socket(AF_INET,SOCK_DGRAM,0); longLType listenAddr; register void *tmp; listenAddr.num=0; listenAddr.list=malloc(sizeof(*listenAddr.list)); if (!listenAddr.list) { nomem: syslog(LOG_ERR,"Out of memory in findListenInterfaces"); return listenAddr; } if (fd<0) { syslog(LOG_ERR,"socket failed in findListenInterfaces: %m"); goto bailout; } ifc.ifc_len = sizeof buf; ifc.ifc_buf = buf; if (ioctl(fd,SIOCGIFCONF,&ifc)<0) { syslog(LOG_ERR,"SIOCGIFCONF failed: %m"); goto bailout; } cplim=buf+ifc.ifc_len; for (i=0,ifreq=ifc.ifc_req;(char*)ifreqifr_name,sizeof(myIfreq.ifr_name)); if (ioctl(fd,SIOCGIFFLAGS,&myIfreq)<0) { syslog(LOG_WARNING,"SIOCGIFFLAGS failed on %s: %m",myIfreq.ifr_name); continue; } if (myIfreq.ifr_flags&IFF_UP) { register int j; for (j=listenAddr.num-1;j>=0;j--) { if (listenAddr.list[j]==((struct sockaddr_in*)&ifreq->ifr_addr)->sin_addr.s_addr) goto next_if; } tmp=realloc(listenAddr.list,(listenAddr.num+1)*sizeof(*listenAddr.list)); if (!tmp) goto nomem; listenAddr.list=tmp; listenAddr.list[listenAddr.num++]=((struct sockaddr_in*)&ifreq->ifr_addr)->sin_addr.s_addr; } next_if: ; } close(fd); bailout: if (!listenAddr.num) listenAddr.list[listenAddr.num++]=htonl(INADDR_ANY); return listenAddr; } /********************************************************************* * * Create the listen socket, and make it non-blocking (everything is * non-blocking). * *********************************************************************/ void createListenSocket(void) { register int s; long sockopt; struct sockaddr_in sin; register fdInfoType *info; register int i; register int numBound=0; longLType addrs; int tmp; memset(&sin,0,sizeof(sin)); if (config.daemon.listenAddr.num) { addrs=config.daemon.listenAddr; } else { addrs=findListenInterfaces(); if (!addrs.num) { syslog(LOG_ERR,"Unable to find interfaces"); exit(2); } } daemonFd=malloc(sizeof(*daemonFd)*(addrs.num+1)); if (!daemonFd) { syslog(LOG_ERR,"Out of memory in createListenSocket"); fprintf(stderr,"Out of memory in createListenSocket"); exit(2); } for (i=0; i=maxFd) { syslog(LOG_ERR,"listen socket out of range"); exit(2); } sockopt=1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt))<0) { perror("setsockopt(reuse)"); syslog(LOG_ERR,"Failed to setsockopt(reuseaddr): %m"); close(s); continue; } sockopt=((config.daemon.flags&FL_NO_KEEPALIVE)==0); if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &sockopt, sizeof(sockopt))<0) { perror("setsockopt(keepalive)"); syslog(LOG_ERR,"Failed to setsockopt(keepalive): %m"); close(s); continue; } sin.sin_family = AF_INET; sin.sin_port = config.daemon.port; sin.sin_addr.s_addr = addrs.list[i]; if (bind(s,(struct sockaddr*)&sin,sizeof(sin))<0) { perror("bind"); syslog(LOG_ERR,"Failed to bind to %s: %m",inet_ntoa(sin.sin_addr)); close(s); continue; } if (listen(s,200)<0) { perror("listen"); syslog(LOG_ERR,"Failed to listen on %s: %m",inet_ntoa(sin.sin_addr)); close(s); continue; } setNonBlocking(s); daemonFd[numBound]=s; info=fdInfo+s; memset(info,0,sizeof(*info)); info->peer=NULL; info->fd=s; info->flags=FD_IS_LISTEN; info->TCP_RECV=listenRecv; setSelect(s,SL_READ|SL_EXCP); syslog(LOG_NOTICE,"listening on [%s].%d",inet_ntoa(sin.sin_addr),ntohs(config.daemon.port)); numBound++; } daemonFd[numBound]=-1; if (!numBound) { syslog(LOG_ERR,"Failed to bind any listen sockets"); exit(2); } if (!config.daemon.listenAddr.num) { free(addrs.list); } } /********************************************************************* * * (Re)read the configuration file and parse it. If all goes well, * replace the current config (if any) with then new config. chdir() * to the specified directory, set the umask, and bump the file limit * if needed (never reduce it). * *********************************************************************/ void readConfig(int sig) { register int newMaxFd; register int oldMaxFd=maxFd; register int oldMaxClient=config.daemon.maxClient; register int newMaxClient; freopen(configFile,"r",stdin); if (!yyparse()) { if (sig) freeConfig(&config); config=newConfig; strncpy(syslogName,config.daemon.name,sizeof(syslogName)); syslogName[sizeof(syslogName)-1]='\0'; chdir(config.daemon.directory); umask(config.daemon.umask); newMaxClient=config.daemon.maxClient; newMaxFd=newMaxClient*2+20+config.daemon.listenAddr.num; if (newMaxFd>maxFd) { register fdInfoType *oldFdInfo=fdInfo, *info; register connInfoType *oldConnInfo=connInfo, *conn; register int i; struct rlimit rp; maxFd=newMaxFd; getrlimit(RLIMIT_NOFILE,&rp); if (maxFd>rp.rlim_max) { maxFd=rp.rlim_max; newMaxClient=config.daemon.maxClient=(maxFd-20-config.daemon.listenAddr.num)/2; if (!sig) { fprintf(stderr,"Too many clients - limited to %d\n",newMaxClient); } else { syslog(LOG_ERR,"Too many clients - limited to %d",newMaxClient); } } rp.rlim_cur=maxFd; setrlimit(RLIMIT_NOFILE,&rp); if (fdInfo) { fdInfo=(fdInfoType*)realloc(fdInfo,maxFd*sizeof(fdInfoType)); if (fdInfo) memset(fdInfo+oldMaxFd,0,(maxFd-oldMaxFd)*sizeof(fdInfoType)); } else { fdInfo=(fdInfoType*)calloc(maxFd,sizeof(fdInfoType)); } if (fdInfo) { for (i=maxFd,info=fdInfo+oldMaxFd;i>oldMaxFd;info++,i--) { info->fd=-1; info->TCP_RECV=(recvFunc*)recv, info->TCP_SEND=(sendFunc*)send, info->excp=nullExcp; } } else { if (!sig) { fprintf(stderr,"Could not allocate fdInfo memory - dying\n"); } else { syslog(LOG_ALERT,"Could not allocate fdInfo memory - dying"); } exit(2); } if (connInfo) { connInfo=(connInfoType*)realloc(connInfo,newMaxClient*sizeof(connInfoType)); if (connInfo) memset(connInfo+oldMaxClient,0,(newMaxClient-oldMaxClient)*sizeof(connInfoType)); } else { connInfo=(connInfoType*)calloc(newMaxClient,sizeof(connInfoType)); } if (!connInfo) { if (!sig) { fprintf(stderr,"Could not allocate connInfo memory - dying\n"); } else { syslog(LOG_ALERT,"Could not allocate connInfo memory - dying"); } exit(2); } #define adjustPtr(ptr,oldBase,newBase,typ) do { \ (ptr) = (typ)((long)(ptr)+(long)(newBase)-(long)(oldBase)); \ } while (0) for (i=0,info=fdInfo; iconn) adjustPtr(info->conn,oldConnInfo,connInfo,connInfoType *); if (info->peer) adjustPtr(info->peer,oldFdInfo,fdInfo,fdInfoType *); } /* just rebuild the freeConn list, while fixing pointers in the * ones that are in use. */ freeConn=NULL; for (i=newMaxClient-1,conn=connInfo+i;i>=0;i--,conn--) { if (conn->flags&CO_IN_USE) { adjustPtr(conn->client,oldFdInfo,fdInfo,fdInfoType*); if (conn->udp) adjustPtr(conn->udp,oldFdInfo,fdInfo,fdInfoType*); } else { conn->client=(fdInfoType*)freeConn; freeConn=conn; } } connSanity(9); #undef adjustPtr } v4Method=findMethod(&config,"v4"); if (sig) syslog(LOG_NOTICE,"Configuration file read"); } else { if (sig) { syslog(LOG_ERR,"configuration file %s failed to parse\n",configFile); freeConfig(&newConfig); } else { fprintf(stderr,"configuration file %s failed to parse. See syslog output.\n",configFile); exit(1); } } } hpsockd-0.17build2/src/sockd/v5udp.c0000644000000000000000000002673711024757214014207 0ustar #include "sockd.h" #include "v5.h" #define RF_LOG_RECORDS_CLIENT 1 #define RF_LOG_RECORDS_PEER 2 #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/v5udp.c,v 0.26 2001/11/14 22:25:50 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ inboundFunc v5UdpCloseInbound; /******************************************************************************** * * How about those various fields in fdInfo, since we now have 4 fd's to play * with... Here are the things of interest. * * client peer udp udpPeer * sin client sin last peer client sin -- * req/user valid -- trashed by validate -- * ********************************************************************************/ int v5DoUdpAssociate(fdInfoType *client) { register fdInfoType *in,*out; register connInfoType *conn=client->conn; register int inFd,outFd,res; struct sockaddr_in srcSin,dstSin,clientSin; register v5HeadType *req=conn->req; register char *m=NULL; register struct sockaddr_in *mSin=NULL; register u_char replyFlags; client->TCP_INBOUND=v5UdpCloseInbound; /* nuke it if we get more data */ clrSelect(client->peer->fd,SL_ALL); footprint(4,client->fd,0,0); switch(conn->req->atyp) { u_int32_t src; ushort port; case ATYP_V4: memcpy(&src,req->destAddr,4); memcpy(&port,req->destAddr+4,sizeof(port)); memset(&dstSin,0,sizeof(dstSin)); dstSin.sin_family=AF_INET; dstSin.sin_addr.s_addr=htonl(INADDR_ANY); /* We don't get destinations until the reqest */ if (!src) { /* Fix the request to point at the client */ memcpy(req->destAddr,&client->sin.sin_addr.s_addr,4); src=client->sin.sin_addr.s_addr; } else if (src != client->sin.sin_addr.s_addr) { return SOCKS5_DENIED; } if ((req->flags&RQ_UDP_USE_CLIENT_PORT) && port>=IPPORT_RESERVED) { dstSin.sin_port=port; replyFlags=RQ_UDP_USE_CLIENT_PORT; } else { dstSin.sin_port=0; replyFlags=0; } memset(&clientSin,0,sizeof(clientSin)); clientSin.sin_family=AF_INET; clientSin.sin_addr.s_addr=src; clientSin.sin_port=port; break; default: return SOCKS5_ADDR_NOT_SUPP; } memset(&srcSin,0,sizeof(srcSin)); srcSin.sin_family=AF_INET; srcSin.sin_addr.s_addr=findRoute(client->sin.sin_addr.s_addr); srcSin.sin_port=0; inFd=createSocket(AF_INET,SOCK_DGRAM,0); if (inFd<0 && errno==EMFILE || inFd>=maxFd) { if (inFd>0) close(inFd); if (spawnChild(conn)==0) return SOCKS5_OK; /* just let the child go home. */ inFd=createSocket(AF_INET,SOCK_DGRAM,0); } if (inFd<0) { m="v5DoUdpAssoc inside socket failed: %m"; goto bailout; } outFd=createSocket(AF_INET,SOCK_DGRAM,0); if (outFd<0 && errno==EMFILE || outFd>=maxFd) { if (outFd>0) close(outFd); if (spawnChild(conn)==0) { close(inFd); return SOCKS5_OK; /* just let the child go home. */ } outFd=createSocket(AF_INET,SOCK_DGRAM,0); } if (outFd<0) { close(inFd); m="v5DoUdpAssoc outside socket failed: %m"; goto bailout; } in=fdInfo+inFd, out=fdInfo+outFd; memset(in,0,sizeof(fdInfoType)); memset(out,0,sizeof(fdInfoType)); conn->udp=in; in->conn=out->conn=conn; in->peer=out, out->peer=in; in->flags=FD_IS_CLIENT|FD_IS_UDP; out->flags=FD_IS_UDP; in->sin=clientSin, memset(&out->sin,0,sizeof(out->sin)); in->fd=inFd, out->fd=outFd; setSocketBuffer(out->fd,conn->bufSize); setSocketBuffer(in->fd,conn->bufSize); in->UDP_RECVFROM=conn->method->recvFrom, out->UDP_RECVFROM=(recvFromFunc*)recvfrom; in->UDP_SENDTO=conn->method->sendTo, out->UDP_SENDTO=(sendToFunc*)sendto; in->excp=nullExcp, out->excp=nullExcp; in->UDP_INBOUND=conn->method->inboundUdp, out->UDP_INBOUND=simpleInboundUdp; in->UDP_OUTPUT=conn->method->outputUdp, out->UDP_OUTPUT=simpleOutputUdp; res=bind(inFd,(struct sockaddr*)&srcSin,sizeof(srcSin)); if (res<0) { m="v5DoUdpAssoc inside bind([%s].%d) failed: %m"; mSin=&srcSin; goto bailout; } res=bind(outFd,(struct sockaddr*)&dstSin,sizeof(dstSin)); if (res<0) { m="v5DoUdpAssoc outside bind([%s].%d) failed: %m"; mSin=&dstSin; goto bailout; } else { int len=sizeof(srcSin); res=getsockname(inFd,(struct sockaddr*)&srcSin,&len); } if (res<0) { m="v5DoUdpAssoc inside getsockname failed: %m"; goto bailout; } setSelect(in->fd,SL_READ|SL_EXCP); setSelect(out->fd,SL_READ|SL_EXCP); v5WriteReply(client,&srcSin,SOCKS5_OK,replyFlags); return SOCKS5_OK; bailout: { register int ret=v5ErrnoToResult(errno); if (mSin) syslog(LOG_ERR,m,inetNtoa(mSin->sin_addr.s_addr),ntohs(mSin->sin_port)); else syslog(LOG_ERR,m); return ret; } } void dumpUDPData(fdInfoType *info,const void *ubuf,unsigned int len, const char *tag) { register int i,j; register const unsigned char *buf=ubuf; static const char chars[]="0123456789abcdef"; static int num=0; char out[2048]; register char *p; num++; while (len) { sprintf(out,"%2s-%05x%c ",tag, num, (i ? '-' : ':')); p=out+10; i=256; while (len>0 && --i) { *p++=chars[*buf>>4]; *p++=chars[*buf&15]; ++buf; if (i%4==0) *p++=' '; --len; } *p=0; syslog(LOG_DEBUG,"%s",out); } } /*************************************************************************** * * We shouldn't receive data on the control connection after the ASSOC * command. If we do, just close the connection. * ***************************************************************************/ /* inboundFunc */ /* ARGSUSED */ void v5UdpCloseInbound(fdInfoType *info,void *buf,int len,unsigned int flags) { pendingClose(info,LOG_TOO_MUCH_DATA); } /*************************************************************************** * * v5InboundUdpReq takes a UDP request from the client and deals with it. * ***************************************************************************/ /* inboundUdpFunc */ /* ARGSUSED */ void v5InboundUdpReq(fdInfoType *info,void *buf,int len,unsigned int flags,const void *vfrom, int fromLen) { register connInfoType *conn=info->conn; register const struct sockaddr_in *from; register v5UdpHeadType *req; /* may not be aligned... */ register int headLen; v5HeadType *validateReq; register int ret; int vfBuf[256]; struct sockaddr_in to; if (conn->ruleFlags&RF_LOG_RECORDS_CLIENT) dumpUDPData(info,buf,len,"IC"); from=vfrom; if (!buf && info->in.bufStart && info->in.dataLen<=sizeof(vfBuf)) { buf=info->in.bufStart; len=info->in.bufSize; fromLen=info->in.dataLen; memcpy(vfBuf,info->in.dataStart,fromLen); from=(const struct sockaddr_in *)vfBuf; free(info->in.dataStart); info->in.bufStart=info->in.dataStart=NULL; info->in.bufSize=info->in.dataLen=0; } if (!buf) { syslog(LOG_ERR,"Entered v5InboundUdpReq with NULL buffer pointer"); return; } req=buf; /* may not be aligned... */ headLen=sizeof(*req)+sizeof(u_short)+ADDRLEN(&req->atyp)-1-sizeof(req->destAddr); /* Verify that the source address matches the expected. Log it and drop if bad */ if (from->sin_family != info->sin.sin_family || from->sin_addr.s_addr != info->sin.sin_addr.s_addr || (info->sin.sin_port && from->sin_port != info->sin.sin_port)) { syslog(LOG_ERR,"Received udp packet from [%s].%d, expected source was [%s].%d, dropped", inetNtoa(from->sin_addr.s_addr), from->sin_port, inetNtoa(info->sin.sin_addr.s_addr), info->sin.sin_port); return; } if (len < headLen) { syslog(LOG_WARNING,"Dropped short packet from [%s].%d", inetNtoa(from->sin_addr.s_addr), ntohs(from->sin_port)); return; } if (req->rsv || req->frag) return; validateReq=malloc(headLen); if (!validateReq) /* out of memory, just drop it.... */ return; memcpy(validateReq,req,headLen); /* Split request into request header and data */ /* XXX - check if this is the same destination as the last one... */ ret=validate(info,VL_ISUDPREQ,&validateReq); if (ret==SOCKS5_TRY_AGAIN) { info->in.bufStart=buf; info->in.bufSize=len; info->in.dataStart=(void*)malloc(fromLen); memcpy(info->in.dataStart,vfrom,fromLen); info->in.dataLen=fromLen; return; /* dns will wake us up again when it's ready, and validate will be able to handle things */ } /* BTW, validateReq may have changed in validate, so use that copy, not a local one... */ if (v5GetSin(validateReq,&to,sizeof(to))!=SOCKS5_OK) goto bail; if (ret==SOCKS5_OK) { /* Toss the data to the peer output routine. */ info->peer->UDP_OUTPUT(info->peer,(caddr_t)buf+headLen,len-headLen,flags,(void*)&to,sizeof(to)); if (info->fd>=0) conn->client->peer->sin=to; } else { syslog(LOG_NOTICE,"Rejected packet from [%s].%d to [%s].%d, validate returned %d", inetNtoa(from->sin_addr.s_addr), ntohs(from->sin_port), inetNtoa(to.sin_addr.s_addr), ntohs(to.sin_port), ret); } bail: free(validateReq); } /*************************************************************************** * * v5OutputUdpReply sends a UDP datagram to the client. * ***************************************************************************/ /* outputUdpFunc */ void v5OutputUdpReply(fdInfoType *info,void *buf,int len,unsigned int flags,const void *from, int fromLen) { double dbuf[65536/sizeof(double)]; register v5UdpHeadType *head=(v5UdpHeadType*)dbuf; register char *c=(char*)dbuf+sizeof(v5UdpHeadType)-sizeof(head->destAddr); if (info->conn->ruleFlags&RF_LOG_RECORDS_CLIENT) dumpUDPData(info,buf,len,"OC"); head->rsv=head->frag=0; c+=v5PutSin(from,fromLen,(v5HeadType*)head); if (head->rsv) /* unsupported address family is the only thing that would do this... */ return; /* drop the packet */ if (c+len > (char*)dbuf+sizeof(dbuf)) /* packet too long */ return; memcpy(c,buf,len), c+=len; info->UDP_SENDTO(info->fd,dbuf,c-(char*)dbuf,flags,&info->sin,sizeof(struct sockaddr_in)); updateTime(info,out,len,now); } /*************************************************************************** * * simpleInboundUdp receives a UDP datagram from the peer. * ***************************************************************************/ void simpleInboundUdp(fdInfoType *info,void *buf,int len,unsigned int flags,const void *from, int fromLen) { if (info->conn->ruleFlags&RF_LOG_RECORDS_PEER) dumpUDPData(info,buf,len,"IP"); info->peer->UDP_OUTPUT(info->peer,buf,len,flags,from,fromLen); } /*************************************************************************** * * simpleOutputUdp sends a UDP datagram to the peer. * ***************************************************************************/ void simpleOutputUdp(fdInfoType *info,void *buf,int len,unsigned int flags,const void *to, int toLen) { if (info->conn->ruleFlags&RF_LOG_RECORDS_PEER) dumpUDPData(info,buf,len,"OP"); (void)info->UDP_SENDTO(info->fd,buf,len,flags,to,toLen); updateTime(info,out,len,now); } hpsockd-0.17build2/src/sockd/v5command.c0000644000000000000000000001707711024757214015032 0ustar #include "sockd.h" #include "v5.h" #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/v5command.c,v 0.13 2002/12/17 05:21:22 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ outputFunc commandOutput; int v5DoCommand(fdInfoType *client,const char *name) { register pid_t pid; register int i; v5HeadType reply; u_short port; register const char *cmd=getEnv(client,name); int pipeFd[2]; register connInfoType *conn=client->conn; if (!cmd) return SOCKS5_CMD_NOT_SUPP; close(client->peer->fd); do { i=pipe(pipeFd); } while (i<0 && errno==EINTR); if (i<0) return SOCKS5_GENFAIL; do { pid=fork(); } while (pid<0 && errno==EINTR); switch (pid) { case -1: close(pipeFd[0]); close(pipeFd[1]); return SOCKS5_GENFAIL; case 0: setpgrp(); close(pipeFd[0]); break; default: conn->pid=-pid; setSelect(client->peer->fd,SL_READ|SL_EXCP); if (pipeFd[0] != client->peer->fd) { dup2(pipeFd[0],client->peer->fd); close(pipeFd[0]); } if (pipeFd[1] != client->peer->fd) close(pipeFd[1]); client->peer->TCP_RECV=(recvFunc*)read; client->peer->TCP_SEND=(sendFunc*)write; client->peer->TCP_OUTPUT=commandOutput; v5GetSin(conn->req,&client->peer->sin,sizeof(client->peer->sin)); return SOCKS5_OK; } if (debug&DBG_CHILD) { volatile int dbg_wait=0; while (!dbg_wait); } memset(&reply,0,sizeof(reply)); reply.version=SOCKS_V5; reply.cmd=SOCKS5_OK; reply.atyp=ATYP_V4; port=htons(0); client->TCP_OUTPUT(client,(char*)&reply,sizeof(reply),0); client->TCP_OUTPUT(client,(char*)&port,sizeof(port),0); for (i=lowFd; i<=highFd; i++) { if (i!=pipeFd[1]) close(i); } dup2(pipeFd[1],1), dup2(pipeFd[1],2), close(pipeFd[1]); freopen("/dev/null","r",stdin); doCommand2(cmd,client); _exit(0); return SOCKS5_OK; /* this is to keep lint happy... */ } int commandOutput(fdInfoType *peer,void *buf, int len, unsigned int flags) { register char *p; register int i; #if 0 /* [ */ /* The client doesn't have stdin open anyway, so don't bother him. */ for (p=buf,i=len;i>0;p++,i--) { switch(*p) { case 'c'&0x1f: kill(peer->conn->pid,SIGINT); break; case 'v'&0x1f: if (i<2) break; i--,p++; /* fall thru */ default: simpleOutput(peer,p,1,flags); break; } } #else kill(peer->conn->pid,SIGINT); #endif /* ] 0 */ return 0; } void doCommand(const char *cmd,fdInfoType *client) { register int pid; if (!(debug&DBG_FOREGROUND)) { do { pid=fork(); } while (pid<0 && errno==EINTR); if (pid < 0) { syslog(LOG_ERR,"doCommand: fork failed %m"); return; } else if (pid) { return; } } /* The child gets here - it's OK to block again... */ doCommand2(cmd,client); } void doCommand2(const char *sCmd,fdInfoType *client) { register connInfoType *conn=client->conn; register char *cmdStart,*cmd,*c; register const char *srcCmd=sCmd,*shell; register int left; register int size; u_short portNum; c=(char*)&conn->req->atyp; c+=ADDRLEN(c); memcpy(&portNum,c,sizeof(u_short)); cmdStart=cmd=malloc(left=size=2048); if (!cmdStart) { syslog(LOG_ERR,"doCommand: malloc failed"); exit(1); } /* walk through the command string, building up our command. Then launch the puppy. */ do { register int len,need; register char *srcName=NULL,*destName=NULL,*servName=NULL; register char *escape=NULL; char escapeBuf[256]; register int warned=0; c=strchr(srcCmd,'%'); len= (c) ? (c-srcCmd) : strlen(srcCmd); if (c) switch(c[1]) { struct hostent *hp; struct servent *sp; case 'A': /* source name */ if (!srcName) { hp=gethostbyaddr((const char *)&client->sin.sin_addr, sizeof(struct in_addr),client->sin.sin_family); if (hp) { srcName=strdup(hp->h_name); } else { goto source_addr; } } if (strlen(srcName)>255) srcName[255]='\0'; escape=srcName; break; case 'a': /* source IP */ source_addr: escape=inet_ntoa(client->sin.sin_addr); break; case 'c': /* command */ switch(conn->req->cmd) { case SOCKS5_CONNECT: escape="connect"; break; case SOCKS5_BIND: escape="bind"; break; case SOCKS5_UDP_ASSOCIATE: escape="udp_assoc"; break; case SOCKS5_PING: escape="ping"; break; case SOCKS5_TRACEROUTE: escape="traceroute"; break; default: escape=escapeBuf; sprintf(escapeBuf,"%d",conn->req->cmd); break; } break; case 'p': /* sockd's pid */ escape=escapeBuf; sprintf(escapeBuf,"%d", getpid()); break; case 'S': /* service name */ if (!servName) { sp=getservbyport(portNum,(client->flags&FD_IS_UDP) ? "udp" : "tcp"); if (sp) { servName=strdup(sp->s_name); } else { sprintf(escapeBuf,"%d",ntohs(portNum)); servName=strdup(escapeBuf); } } escape=servName; break; case 's': /* service num */ escape=escapeBuf; sprintf(escapeBuf,"%d",ntohs(portNum)); break; case 'u': /* user name */ escape=conn->user ? conn->user : "(NONE)"; break; case 'Z': /* destination name */ if (!destName) { switch(conn->req->atyp) { case ATYP_V4: hp=gethostbyaddr((const char *)&conn->req->destAddr, sizeof(conn->req->destAddr),AF_INET); break; case ATYP_V6: default: hp=NULL; break; } if (hp) { destName=strdup(hp->h_name); } else { goto dest_addr; } } if (strlen(destName)>255) destName[255]='\0'; escape=destName; break; case 'z': /* destination IP */ dest_addr: switch(conn->req->atyp) { case ATYP_V4: escape=inet_ntoa(*(struct in_addr*)&conn->req->destAddr); break; case ATYP_V6: escape="V6 address"; break; default: escape="Unknown address type"; break; } break; default: escape=escapeBuf; escapeBuf[0]=*c, escapeBuf[1]=c[1], escapeBuf[2]='\0'; break; } need=len+strlen(escape); while (need+40>left) { /* some slop for next time through */ register int pos=cmd-cmdStart; #define BUMP_AMOUNT 500 left+=BUMP_AMOUNT; cmdStart=realloc(cmdStart,(size+=BUMP_AMOUNT)); if (!cmdStart) { syslog(LOG_ERR,"doCommand: realloc failed"); exit(1); } cmd=cmdStart+pos; #undef BUMP_AMOUNT } strncpy(cmd,srcCmd,len), srcCmd+=len+2, cmd+=len; if (escape) { register char *p; for (p=escape; *p; p++) if (strchr("{}[]%^;$#!`~&*()\"'<>|\\/=",*p) || *p<=' ') { if (!warned) { syslog(LOG_WARNING,"Possible shell escape in %s",escape); warned=1; } *p='_'; } strcpy(cmd,escape), cmd+=strlen(escape); } } while (c); shell=getEnv(client,"SHELL"); if (!shell) shell="/bin/sh"; if (!(debug&DBG_FOREGROUND)) { execl(shell,"sh","-c",cmdStart,(char*)NULL); syslog(LOG_ERR,"exec failed (%m) %s -c %s",shell,cmdStart); } else { system(cmdStart); free(cmdStart); } } hpsockd-0.17build2/src/sockd/dns.c0000644000000000000000000003035611024757214013720 0ustar #include "sockd.h" #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/dns.c,v 0.28 2001/12/29 06:12:33 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ typedef struct dnsReq dnsReqType; typedef struct dnsReply dnsReplyType; sendFunc dnsWrite; /***************************************************************************** * * The philosophy here is that one (or more) helper process(es) accept * requests on a port bound to 127.0.0.1, do the dns lookups, and then fire * the answer back to the guy who asked the question. That sockd then * sanitizes the answer, and redoes the request processing, which * successfully hits the one entry cache in sockd, and things go from there. * * The basic flow is sockd -> dnsQuery -> sendto (return -1 -> SOCKS5_TRY_AGAIN) * dnsHandler -> recvFrom -> gethostbyname -> sendto * (sockd) mainLoop -> dnsRecv -> client->output -> dnsQuery(returns) * * At some point, we should consider doing reverse lookups, but for now we * just have room in the structure, but no code behind it. *****************************************************************************/ struct dnsReq { int clientFd; int type; #define DNS_QUERY 1 #define DNS_IQUERY 2 union { char name[256]; struct { int type; int len; /* actual length of addr */ char addr[248]; } addr; } req; }; struct dnsReply { int clientFd; long bias; /* &hostent when pointers were calculated */ struct hostent hostent; }; void dnsHandler(int fd); fdInfoType *dnsInfo; /***************************************************************************** * * dnsGlobalInit() does the global initialization of the dns helper processes. * When it's done, dnsAddr holds the address of the helpers (who all listen * on the same address), and the helpers are all running. * *****************************************************************************/ struct sockaddr_in dnsAddr; void dnsGlobalInit(void) { register int s; struct sockaddr_in sin; int sinLen; register int i; register int res; if (!config.daemon.numHelper) return; s=socket(AF_INET,SOCK_DGRAM,0); if (s<0) { syslog(LOG_ERR,"dns socket: %m"); exit(2); } if (s>=maxFd) { syslog(LOG_ERR,"dns socket out of range"); exit(2); } memset(&sin,0,sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = 0; sin.sin_addr.s_addr = inet_addr("127.0.0.1"); if (bind(s,(struct sockaddr*)&sin,sizeof(sin))<0) { perror("bind"); exit(2); } sinLen=sizeof(dnsAddr); do { res=getsockname(s,&dnsAddr,&sinLen); } while (res<0 && errno==EINTR); for (i=config.daemon.numHelper; i>0; i--) { register int pid; do { pid=fork(); } while (pid<0 && errno==EINTR); if (pid==0) { register int j; for (j=0;daemonFd[j]>=0;j++) { close(daemonFd[j]); } free(daemonFd); setupSignals(0); setCommandLine("sockd --dnsHandler"); if (debug&DBG_DNS) { /* let the debugger come find us */ volatile int debugSpin=0; while (!debugSpin); } dnsHandler(s); return; } else if (pid<0) { syslog(LOG_ERR,"fork(dnsHelper) failed: %m"); break; } } close(s); } /***************************************************************************** * * dnsServerInit() does the initialization of the sockd half of things, and * gets called once per server from setupDaemon(). After this point, we can * send queries to the dns helper. * *****************************************************************************/ void dnsServerInit(void) { register int s; struct sockaddr_in sin; register fdInfoType *info; register int oldS=-1; if (!config.daemon.numHelper) return; if (dnsInfo) { oldS=dnsInfo->fd; forgetInfo(dnsInfo); } s=socket(AF_INET,SOCK_DGRAM,0); if (s<0) { syslog(LOG_ERR,"dns socket: %m"); exit(2); } if (s>=maxFd) { syslog(LOG_ERR,"dns socket out of range"); exit(2); } footprint(8,s,oldS,0); memset(&sin,0,sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = 0; sin.sin_addr.s_addr = inet_addr("127.0.0.1"); if (bind(s,(struct sockaddr*)&sin,sizeof(sin))<0) { perror("bind"); exit(2); } if (connect(s,(struct sockaddr*)&dnsAddr,sizeof(dnsAddr))<0) { perror("connect"); exit(2); } setNonBlocking(s); dnsInfo=info=fdInfo+s; memset(info,0,sizeof(*info)); /* info->peer=NULL; */ info->fd=s; info->flags=FD_IS_SPECIAL|FD_IS_UDP; info->UDP_RECVFROM=(recvFromFunc*)recvfrom, info->UDP_SENDTO=(sendToFunc*)sendto, info->excp=nullExcp; info->UDP_INBOUND=dnsInboundUdp; /* info->UDP_OUTPUT=NULL; */ setSelect(s,SL_READ|SL_EXCP); } /***************************************************************************** * * adjust() is just a longwinded way of making sure that the pointers are * sane before we go for broke... It adjusts the pointers to their rightful * values. Returns 0 for OK, -1 for failure (bogus value). * *****************************************************************************/ static int adjust(void*uptr,void *start,int len,void *newStart) { register void **ptr=uptr; register long lptr=(long)*ptr; if (!*ptr) return 0; /* Handle the NULL pointer */ /* make sure it's inside the range */ if (*ptr(void*)((char*)start+len)) return -1; lptr+=(long)newStart-(long)start; *ptr=(void*)lptr; return 0; } /* dnsSaveReply is the one entry cache for dns lookups. */ struct hostent *dnsSaveReply; /***************************************************************************** * * dnsInboundUdp() is an inboundUdpFunc attached to the dns UDP request port * * Do a few sanity checks on the reply, adjust the pointers, and save it away. * Then we call peer->output (v5Request most likely) with no data, just to * tickle him into trying the request again. He'll call dnsQuery(), which * will match dnsSaveReply, and he'll have his answer. Ugly, but it keeps * things looking clean in the main code. * *****************************************************************************/ /* inboundUdpFunc */ /* ARGSUSED */ void dnsInboundUdp(fdInfoType *info,void *buf,int len,unsigned int flg, const void *vFrom, int fromLen) { dnsReplyType *reply=buf; register fdInfoType *peer; register fdInfoType *client; register int clientFd=ntohl(reply->clientFd); register int i; const struct sockaddr_in *from=vFrom; /* Make sure that the packet arrived from dnsAddr */ if (from->sin_port != dnsAddr.sin_port || from->sin_addr.s_addr != dnsAddr.sin_addr.s_addr) { syslog(LOG_ERR,"DNS reply from unexpected address: %s %d",inet_ntoa(from->sin_addr),ntohs(from->sin_port)); return; } if (len==0) { if (!pendingTerm) syslog(LOG_ERR,"Got end of file from DNS handler"); dnsDestroy(); unListen(1); /* Don't take any more clients, since we can't handle ATYP_DOMAIN */ return; } if (clientFd>=lowFd && clientFd<=maxFd) { peer=fdInfo+clientFd; client=peer->peer; } else { bail: syslog(LOG_ERR,"Bogus reply to dnsReply"); return; } if (!client || client->fd<0) { syslog(LOG_WARNING,"Received DNS reply for closed connection"); return; } if (adjust(&reply->hostent.h_name,(void*)reply->bias,len,&reply->hostent)) goto bail; /* the h_addr_list pointer needs to be aligned. */ if (adjust(&reply->hostent.h_addr_list,(void*)reply->bias,len,&reply->hostent) || ((long)reply->hostent.h_addr_list&(sizeof(void*)-1))) goto bail; if (reply->hostent.h_addr_list) { for (i=0;reply->hostent.h_addr_list[i]; i++) { if (adjust(&reply->hostent.h_addr_list[i],(void*)reply->bias,len,&reply->hostent)) goto bail; } } dnsSaveReply=&reply->hostent; setSelect(client->fd,SL_READ); /* we shut him down earlier */ if (!(client->flags&FD_IS_UDP)) { client->TCP_INBOUND(client,NULL,0,0); } else { client->UDP_INBOUND(client,NULL,0,0,NULL,0); } return; } /***************************************************************************** * * dnsQuery() does non-blocking dns resolution, the hard way. Rather than * figure out packet formats and all that, we toss it over to a helper process * (or more), which do the lookup and fire the answer back at us. This answer * gets cached and the caller is told to retry. Consequently, if we have a * cached answer, then we just give them the answer. If not, fire off the * question to the helper process. * *****************************************************************************/ struct hostent *dnsQuery(char *name, fdInfoType *peer) { double dbuf[1024/sizeof(double)]; dnsReqType *req=(dnsReqType*)dbuf; register struct hostent *hent=dnsSaveReply; if (!config.daemon.numHelper) return NULL; if (hent) { dnsSaveReply=NULL; if (hent->h_addr_list==NULL) hent=NULL; return hent; } if (!dnsInfo) /* No more DNS lookups */ return NULL; req->clientFd=htonl(peer->fd); req->type=DNS_QUERY; if (strlen(name)>255) return NULL; strcpy(req->req.name,name); req->req.name[255]='\0'; dnsWrite(dnsInfo->fd,req,sizeof(*req),0); return (struct hostent *)-1; } /***************************************************************************** * * dnsHandler() is just an infinite loop reading requests from his socket, * doing the lookup, and then returning the answer to the guy who asked. * *****************************************************************************/ void dnsHandler(int fd) { double sbuf[1024/sizeof(double)]; double dbuf[1024/sizeof(double)]; register dnsReqType *req=(dnsReqType*)sbuf; register dnsReplyType *reply=(dnsReplyType*)dbuf; register char *limit=(char*)dbuf+sizeof(dbuf); register struct hostent *hent; struct sockaddr_in from; int fromLen; while (1) { register char *next=(char*)(reply+1); register int ret; do { fromLen=sizeof(from); ret=recvfrom(fd,sbuf,sizeof(sbuf),0,&from,&fromLen); } while (ret<0 && errno==EINTR); if (ret<0) break; if (ret != sizeof(*req)) { syslog(LOG_ERR,"dnsHandler: bad size request (%d)"); continue; } memset(dbuf,0,sizeof(dbuf)); reply->clientFd=req->clientFd; req->req.name[255]='\0'; reply->bias=(long)&reply->hostent; reply->hostent.h_name=next; strcpy(next,req->req.name); next+=strlen(req->req.name)+1; hent=gethostbyname(req->req.name); if (hent) { register int i,j; for (i=0;hent->h_addr_list[i];i++); reply->hostent.h_addr_list=(char**)((long)(next+(sizeof(char**)-1))&~(sizeof(char**)-1)); next=(char*)(reply->hostent.h_addr_list+i+1); if (next+hent->h_length*i>limit) { i=(limit-next)/hent->h_length; } for (j=0;jhostent.h_addr_list[j]=next; memcpy(next,hent->h_addr_list[j],hent->h_length); next+=hent->h_length; } reply->hostent.h_addrtype=hent->h_addrtype; reply->hostent.h_length=hent->h_length; } else { reply->hostent.h_addr_list=(char**)NULL; } sendto(fd,dbuf,next-(char*)dbuf,0,&from,fromLen); } syslog(LOG_ERR,"dnsHandler dying: %m"); } /***************************************************************************** * * dnsDestroy() is called from the top of destroyDaemon (in sockd) to get rid * of the connection to the dns helper. * *****************************************************************************/ void dnsDestroy(void) { register int fd; if (!dnsInfo) return; fd=dnsInfo->fd; if (fd<0) { return; } closeConnection(dnsInfo,LOG_CLOSE,0); dnsInfo=NULL; } /* ARGSUSED */ ssize_t dnsWrite(int fd, const void *buf,size_t count,unsigned int flg) { return write(fd,buf,count); } hpsockd-0.17build2/src/sockd/sockd.conf.debian0000644000000000000000000000306211024757214016155 0ustar daemon { # name "sockd"; # listen-address { 0.0.0.0; }; directory "/var/cache/hpsockd"; negotiate-file "negot_file"; # must be specified # inetdsec-file "/var/adm/inetd.sec"; # default is no inetd.sec # listen {1,252}; # client {1,200}; # pre-fork 1; # service "socks"; # port 1080; # poll 1m; # user -2; user "nobody"; # dns-helper 1; # flags { }; }; logging { # facility "daemon"; # level 2; dump-prefix "sockd.dump"; # if not specified, you get no dumps usage-log "usage.log"; # if not specified, you get no logging }; env { PING="/bin/ping %z"; TRACEROUTE="/usr/sbin/traceroute %z"; }; default { # timeout 2h; # setup-timeout 15m; # bufsize 32768; }; route { { default host }; # must have at least one route }; method-list { { number 0; name "noAuth"; internal; flags 0; }; { number 2; name "userPass"; internal; flags 0; }; { number 254; name "v4"; internal; flags 0; }; }; client-method { { src { @@MYNET@@/@@NETSIZE@@; }; method { "userPass"; "v4"; "noAuth"; }; }; }; client { permit traceroute { # Let net @@MYNET@@ traceroute even net @@MYNET@@. src { @@MYNET@@/@@NETSIZE@@; }; }; deny { # block X traffic port { 6000-6099; }; }; deny { # Nothing bound for net @@MYNET@@, or private dest { @@MYNET@@/@@NETSIZE@@; 127/8; 10/8; 172.16/12; 192.168/16; }; }; permit { # give ftp control sessions longer src { @@MYNET@@/@@NETSIZE@@; }; port { "ftp"; }; timeout 1d; }; permit { # Let net @@MYNET@@ out src { @@MYNET@@/@@NETSIZE@@; }; timeout 1h; }; deny { }; # nuke everyone else (default action) }; hpsockd-0.17build2/src/sockd/v4.c0000644000000000000000000002113211024757214013455 0ustar #include "sockd.h" #include "v4.h" #include "v5.h" /* we convert requests for fdInfo */ #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/v4.c,v 0.33 2000/12/08 20:47:24 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ v5HeadType *makeV5Req(v4HeadType *req, dataBufType *buf); sendFunc v4ConnectSendReply; recvFunc v4BindRecv; int v4Info(methodInfoType *info,int version) { if (version!=METHOD_VERSION) return -1; info->negotiate=newV4Client; #ifdef FULLMETHOD info->TCP_INBOUND=simpleInbound; info->TCP_OUTPUT=simpleOutput; #endif return 0; } methodInfoType *v4Method; /* inboundFunc */ void newV4Client(fdInfoType *client,void *buf,int len,unsigned int flags) { register char *p; register v4HeadType *req; register int l=ofs(v4HeadType,user); u_char dest[5]; register methodInfoType *method; register fdInfoType *peer=client->peer; register int ret; register connInfoType *conn=client->conn; #ifdef __lint l=flags; #endif addToBuffer(client,&client->in,buf,len); if (client->in.dataLen<=l) return; for (p=client->in.dataStart+l;lin.dataLen && *p;l++,p++); if (l>=client->in.dataLen) return; /* We have a complete request */ req=malloc(l+1); if (!req) { freeSomeMemory(&client->in); req=malloc(l+1); } if (req) { getFromBuffer((char*)req,&client->in,l+1,0); conn->req=makeV5Req(req,&client->in); conn->user=strdup(req->user); if (conn->req && v4Method) { u_char methData[3]={SOCKS_V4,1,0}; methData[2]=v4Method->num; method=findMatchingMethod(&client->sin,methData); } else { method=NULL; } } else { method=NULL; } if (!method) { v4HeadType reply; reply.version=SOCKS_V4; reply.cmd=SOCKS4_FAIL; client->TCP_OUTPUT(client,(char*)&reply,ofs(v4HeadType,user),0); pendingClose(client,LOG_NOMETHOD); goto leave; } conn->method=method; *dest=ATYP_V4; memcpy(dest+1,&req->destIP,4); logStartup(client); ret=validate(client,VL_NONE,NULL); if (ret!=SOCKS5_OK) { v4HeadType reply; reply.version=SOCKS_V4; reply.cmd=SOCKS4_FAIL; v5GetSin(conn->req,&peer->sin,sizeof(peer->sin)); client->TCP_OUTPUT(client,(char*)&reply,ofs(v4HeadType,user),0); pendingClose(client,ret); goto leave; } setupTimeouts(conn,conn->timeOut); setSocketBuffer(peer->fd,conn->bufSize); setSocketBuffer(client->fd,conn->bufSize); client->TCP_INBOUND=simpleInbound; client->TCP_OUTPUT=simpleOutput; switch(req->cmd) { case SOCKS_CONNECT: v4DoConnect(client,req); break; case SOCKS_BIND: v4DoBind(client,req); break; default: syslog(LOG_ERR,"Bad v4 command %d from %s", req->cmd,inet_ntoa(client->sin.sin_addr)); pendingClose(client,LOG_PROTOCOL_ERROR); goto leave; } leave: if (req) free(req); } void v4DoConnect(fdInfoType *client,v4HeadType *req) { struct sockaddr_in sin; register fdInfoType *peer=client->peer; register int outFd=peer->fd; register int res; clrSelect(client->fd,SL_READ); memset(&sin,0,sizeof(sin)); sin.sin_family=AF_INET; sin.sin_addr.s_addr=req->destIP; sin.sin_port=req->port; peer->sin=sin; peer->TCP_INBOUND=simpleInbound; peer->TCP_OUTPUT =simpleOutput; setSelect(outFd,SL_READ|SL_EXCP); res=connect(outFd,(struct sockaddr*)&sin,sizeof(sin)); if (res==0 || res<0 && errno==EINPROGRESS) { peer->TCP_SEND=v4ConnectSendReply; setSelect(outFd,SL_WRITE); } else { v4ConnectSendReply(outFd,(const void *)NULL,0,0); /* just send it now */ } } /* sendFunc */ /* ARGSUSED */ ssize_t v4ConnectSendReply(int fd, const void *buf,size_t count,unsigned int flg) { register fdInfoType *peer=fdInfo+fd; register fdInfoType *client=peer->peer; register int res; v4HeadType reply; struct sockaddr_in sin; int sinlen=sizeof(sin); peer->TCP_SEND=(sendFunc*)send; peer->TCP_INBOUND=simpleInbound; res=connect(fd,(struct sockaddr*)&client->sin,sizeof(client->sin)); memset((char*)&reply,0,sizeof(reply)); memset(&sin,0,sizeof(sin)); #ifdef ONLY_GOOD_CLIENTS reply.version=SOCKS_V4; #else reply.version=0; /* Lots of idiot clients expect 0 instead of 4. */ #endif setSelect(client->fd,SL_READ); if (res==0 || errno==EISCONN) { reply.cmd=SOCKS4_RESULT; res=getsockname(fd,(struct sockaddr*)&sin,&sinlen); reply.port=sin.sin_port; reply.destIP=sin.sin_addr.s_addr; } else { reply.cmd=SOCKS4_FAIL; } client->TCP_OUTPUT(client,(char*)&reply,ofs(v4HeadType,user),0); if (reply.cmd==SOCKS4_FAIL) { pendingClose(client,LOG_ERRNO+errno); } return 0; } void v4DoBind(fdInfoType *client,v4HeadType *req) { register fdInfoType *peer=client->peer; register int outFd=peer->fd,res; struct sockaddr_in sin; int len=sizeof(sin); v4HeadType reply; memset(&reply,0,sizeof(reply)); #ifdef ONLY_GOOD_CLIENTS reply.version=SOCKS_V4; #else reply.version=0; /* Lots of idiot clients expect 0 instead of 4. */ #endif reply.cmd=SOCKS4_RESULT; peer->TCP_INBOUND=simpleInbound; peer->TCP_OUTPUT =simpleOutput; setSelect(outFd,SL_READ|SL_EXCP); memset(&sin,0,sizeof(sin)); sin.sin_family=AF_INET; sin.sin_addr.s_addr=findRoute(req->destIP); sin.sin_port=0; res=bind(outFd,(struct sockaddr*)&sin,sizeof(sin)); if (res<0) { syslog(LOG_ERR,"v4DoBind bind failed: %m"); bDie: reply.cmd=SOCKS4_FAIL; client->TCP_OUTPUT(client,(char*)&reply,ofs(v4HeadType,user),0); pendingClose(client,LOG_ERRNO+errno); return; } res=getsockname(outFd,(struct sockaddr*)&sin,&len); if (res<0) { syslog(LOG_ERR,"v4DoBind getsockname failed: %m"); goto bDie; } v5GetSin(client->conn->req,&peer->sin,sizeof(peer->sin)); /* put the request address here for now. */ reply.destIP=sin.sin_addr.s_addr; reply.port=sin.sin_port; client->TCP_OUTPUT(client,(char*)&reply,ofs(v4HeadType,user),0); if (client->fd<0) return; res=listen(outFd,1); peer->TCP_RECV=v4BindRecv; setSelect(outFd,SL_READ|SL_EXCP); } /* recvFunc */ /* ARGSUSED */ ssize_t v4BindRecv(int fd, void *buf,size_t count,unsigned int flags) { struct sockaddr_in sin; int len=sizeof(sin); register int newFd; register fdInfoType *peer=fdInfo+fd; register fdInfoType *client=peer->peer; register connInfoType *conn=peer->conn; v4HeadType reply; struct sockaddr_in din; memset(&reply,0,sizeof(reply)); #ifdef ONLY_GOOD_CLIENTS reply.version=SOCKS_V4; #else reply.version=0; /* Lots of idiot clients expect 0 instead of 4. */ #endif reply.cmd=SOCKS4_RESULT; newFd=accept(fd,(struct sockaddr*)&sin,&len); if (newFd<0) { syslog(LOG_WARNING,"v4BindRecv accept failed: %m"); return -1; } dup2(newFd,fd); close(newFd); setSocketBuffer(fd,conn->bufSize); setNonBlocking(fd); peer->sin=sin; peer->TCP_RECV=(recvFunc*)recv; v5GetSin(conn->req,&din,sizeof(din)); /* put the request address here for now. */ if (ntohl(din.sin_addr.s_addr) != 0xffffffff && ntohl(din.sin_addr.s_addr) !=0 && sin.sin_addr.s_addr != din.sin_addr.s_addr) { syslog(LOG_ERR,"v4BindRecv received connection from %s, expected connection from %s", inetNtoa(sin.sin_addr.s_addr), inetNtoa(din.sin_addr.s_addr)); reply.cmd=SOCKS4_FAIL; client->TCP_OUTPUT(client,(char*)&reply,ofs(v4HeadType,user),0); errno=EACCES; return -1; } reply.port=sin.sin_port; reply.destIP=sin.sin_addr.s_addr; client->TCP_OUTPUT(client,(char*)&reply,ofs(v4HeadType,user),0); return -2; } v5HeadType *makeV5Req(v4HeadType *req, dataBufType *buf) { register v5HeadType *v5; v5=malloc(sizeof(v5HeadType)+2); if (!v5) { freeSomeMemory(buf); v5=malloc(sizeof(v5HeadType)+2); if (!v5) return NULL; } v5->version = SOCKS_V5; v5->cmd = req->cmd; v5->flags = 0; v5->atyp = ATYP_V4; memcpy(&v5->destAddr,&req->destIP,4); memcpy(v5+1,&req->port,sizeof(req->port)); return v5; } hpsockd-0.17build2/src/sockd/sockd.h0000644000000000000000000004056111024757214014243 0ustar /* @(#)$Header: /var/cvs/hpsockd/src/sockd/sockd.h,v 0.67 2002/03/28 19:04:26 lamont Exp $ */ #ifndef SOCKD_H_INCLUDED #define SOCKD_H_INCLUDED /* (c) Copyright Hewlett-Packard Company 1997-2000. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #ifndef SHUT_RDWR #define SHUT_RDWR 2 #endif #include #include #include #include #include #include #include #include #include #ifndef SIGEMT #define SIGEMT SIGFPE #endif #include #include "paths.h" #include "inet_ntoa.h" #ifdef HAVE_MMAP #include #ifndef MAP_FILE #define MAP_FILE 0 #endif #endif #ifndef SUPPORT_IP6 #undef AF_INET6 #endif #ifdef MSEM_UNLOCKED #define HAVE_MSEM #else #include #endif #ifdef __hpux #define setuid(x) setresuid((x),(x),(x)) #define setgid(x) setresgid((x),(x),(x)) #endif #ifdef USE_SIGNALS #define SIGWAKEUP SIGWINCH #endif typedef struct dataBuf dataBufType; typedef struct fdInfo fdInfoType; typedef struct connInfo connInfoType; typedef struct sockdLog sockdLogType; typedef volatile struct negotPage negotPageType; typedef volatile struct negotInfo negotInfoType; typedef volatile struct negotHead negotHeadType; typedef struct timeOutHead timeOutHeadType; typedef struct daemonInfo daemonInfoType; typedef struct logInfo logInfoType; typedef struct defaultInfo defaultInfoType ; typedef struct configInfo configInfoType; typedef struct clientInfo clientInfoType; typedef enum relop { r_eq, r_ne, r_lt, r_le, r_gt, r_ge } relopType; typedef struct host hostType; typedef struct routeInfo routeInfoType; typedef struct port portType; typedef struct methodInfo methodInfoType; typedef struct clientMethodInfo clientMethodInfoType; typedef struct intMethInfo intMethInfoType; typedef void (inboundFunc)(fdInfoType *info,void *buf,int len,unsigned int flags); typedef int (outputFunc)(fdInfoType *info,void *buf,int len,unsigned int flags); typedef ssize_t (recvFunc)(int fd, void *buf,size_t count,unsigned int flg); typedef ssize_t (sendFunc)(int fd, const void *buf,size_t count,unsigned int flg); typedef void (inboundUdpFunc)(fdInfoType *info,void *buf,int len,unsigned int flags,const void *from, int fromLen); typedef void (outputUdpFunc)(fdInfoType *info,void *buf,int len,unsigned int flags,const void *to, int toLen); typedef ssize_t (recvFromFunc)(int fd, void *buf,size_t count,unsigned int flg,void *from, int *fromLen); typedef ssize_t (sendToFunc)(int fd, const void *buf,size_t count,unsigned int flg,const void *to, int toLen); typedef void (excpFunc)(fdInfoType *info); typedef int (infoFunc)(methodInfoType* info,int version); #define listType(stru,typdef,type) typedef struct stru { int num; type *list; } typdef; listType(longList,longLType,long) listType(hostList,hostLType,hostType) listType(portList,portLType,portType) listType(strList, strLType,char *) listType(clInList,clInLType,clientInfoType) listType(rtInList,rtInLType,routeInfoType) listType(cmInList,cmInLType,clientMethodInfoType) listType(mInfList,mInfLType,methodInfoType) listType(mInPList,mInPLType,methodInfoType *) #define ofs(tp,field) (int)(&(((tp*)0)->field)) #define bumpHighLow(fd) do { \ if (fd>highFd) highFd=fd; if (fd0) (who)->which.totalBytes += (len); \ if ((who)->conn && (who)->conn->expire) \ (who)->conn->expire = (when)+(who)->conn->timeOut; \ } while (0) #define milliSleep(mSec) do { \ int i=(mSec); \ struct timeval tv; tv.tv_sec=i/1000; tv.tv_usec=(i%1000)*1000; \ select(0,NULL,NULL,NULL,&tv); \ } while (0) struct dataBuf { char *bufStart, /* first byte of buffer */ *dataStart; /* first valid data byte */ int dataLen, /* number of valid data bytes */ bufSize; /* size of buffer */ long totalBytes; /* total bytes (encapsulated) through */ }; struct connInfo { fdInfoType *client; /* TCP connection controlling a UDP port, if any, */ /* When on free list, this is the ptr to next */ fdInfoType *udp; /* UDP half of UDP associate connections */ struct v5Head *req; /* v5 formated request, freed at close */ char *user; /* authenticated user name, freed at close */ time_t startTime; /* startup time for this socket */ pid_t pid; /* pid to kill (if any) */ int timeOut; /* inactivity timeout, in seconds */ time_t expire; /* When do we expire? */ int bufSize; /* based on client rule, from validation */ int logId; /* set by logStartup */ methodInfoType *method; /* Used to log method number in startup */ int flags; #define CO_CLOSE_PENDING 0x00000001 #define CO_IN_USE 0x00000002 #define CO_SANITY_HIT 0x00010000 int ruleFlags; /* flags from rule, method specific */ int error; }; struct fdInfo { fdInfoType *peer; /* Who are we talking to? */ connInfoType *conn; /* Connection global information */ volatile int fd; /* our socket */ int flags; #define FD_IS_LISTEN 0x00000001 /* This is the listen socket */ #define FD_IS_UDP 0x00000002 /* UDP (not TCP) socket */ #define FD_SHUTDOWN 0x00000004 /* flushing wrt data for close */ #define FD_IS_CLIENT 0x00000008 /* This is the client half of the link */ #define FD_IS_SPECIAL 0x00000010 /* it's wierd.. */ #define FD_SANITY_HIT 0x00010000 /* used in sanity check. */ struct sockaddr_in sin; /* who is on the other end of this socket */ union { struct { inboundFunc *inbound; /* inbound() is handed a buffer of unprocessed input data from recv(), * which it must completely consume, possibly into in. */ outputFunc *output; /* output() is handed a buffer of unencapsulated data to be packed * and sent, which it must completely consume, possibly into out. * If data is queued in out (only because of a partial write to the * socket, then the write select flag must be set by output(). The * outer loop will then do the write() calls itself. */ recvFunc *recv; sendFunc *send; } fdiTcp; struct { inboundUdpFunc *inboundUdp; /* inbound() is handed a buffer of unprocessed input data from recv(), * which it must completely consume, possibly into in. */ outputUdpFunc *outputUdp; /* output() is handed a buffer of unencapsulated data to be packed * and sent, which it must completely consume, possibly into out. * If data is queued in out (only because of a partial write to the * socket, then the write select flag must be set by output(). The * outer loop will then do the write() calls itself. */ recvFromFunc *recvFrom; sendToFunc *sendTo; } fdiUdp; } uFuncs; excpFunc *excp; dataBufType in; /* unprocessed inbound data */ dataBufType out; /* unsent, processed outbound data */ }; #define TCP_INBOUND uFuncs.fdiTcp.inbound #define TCP_OUTPUT uFuncs.fdiTcp.output #define TCP_RECV uFuncs.fdiTcp.recv #define TCP_SEND uFuncs.fdiTcp.send #define UDP_INBOUND uFuncs.fdiUdp.inboundUdp #define UDP_OUTPUT uFuncs.fdiUdp.outputUdp #define UDP_RECVFROM uFuncs.fdiUdp.recvFrom #define UDP_SENDTO uFuncs.fdiUdp.sendTo struct negotInfo { pid_t pid; int numConn; int flags; #define NF_LOSER 1 /* can never be the listener - not set in negot page.*/ time_t lastChecked; }; #define NEGOT_SIZE 4096 #define LI_BITSPERINT (sizeof(int)*8) #define LI_SET(slot,listn) (listn[(slot)/LI_BITSPERINT]|=(1<<(slot%LI_BITSPERINT))) #define LI_CLR(slot,listn) (listn[(slot)/LI_BITSPERINT]&=~(1<<(slot%LI_BITSPERINT))) #define LI_ISSET(slot,listn) (listn[(slot)/LI_BITSPERINT]&(1<<(slot%LI_BITSPERINT))) struct negotHead { #ifdef HAVE_MSEM msemaphore sema; #else int semId; #endif pid_t processGroup; int numListen; /* how many listening */ int listeners[(NEGOT_SIZE+sizeof(negotInfoType)-1)/sizeof(negotInfoType)/LI_BITSPERINT]; }; #define NEGOT_MAXSLOT ((NEGOT_SIZE-sizeof(negotHeadType))/sizeof(negotInfoType)) struct negotPage { negotHeadType head; negotInfoType slot[NEGOT_MAXSLOT]; }; struct timeOutHead { fdInfoType *first,*last; }; struct daemonInfo { int minListen,maxListen; int minClient,maxClient; int preFork; int numHelper; uid_t uid; gid_t gid; longLType listenAddr; char *service; /* name of service */ int port; /* network byte order */ int umask; char *directory; /* chdir here before working */ char *name; /* name for syslog */ char *negotFile; char *inetdSecFile; int poll; int flags; int milliPerClient; /* Average distance in time between accepts */ }; #define FL_NO_KEEPALIVE 0x0001 /* Don't do keepalives */ #define FL_V4_ONLY 0x8000 struct logInfo { int level; /* how verbose are we */ int facility; char *logFile; /* name of log file */ char *dumpPrefix; }; struct defaultInfo { int bufSize; int timeOut; int setupTimeOut; }; struct host { relopType op; long value,mask; /* value&mask == addr&mask --> hit */ }; struct routeInfo { hostType host; long ip; }; struct port { u_short low,high; /* low<=port<=high --> hit */ }; #define METHOD_VERSION 0 struct methodInfo { char *name; u_char num; char *libName; infoFunc *info; strLType env; /* method specific environment variables */ int flags; /* user specified flags for method. These are left completely to the method. */ /* The following are filled in by the info routine (if version==METHOD_VERSION). * Initially, info->inbound=negotiate, and info->output=simpleOutput. Once method negotiation * is complete, the inbound and output functions must be changed to point to the encapsulation * versions of the routines. If you have no method specific negotiation, just set negotiate * to the inbound function. * * Likewise, the UdpAssoc routine will change things to point to the UDP versions if that's * where we go. */ inboundFunc *negotiate; inboundUdpFunc *inboundUdp; outputUdpFunc *outputUdp; recvFromFunc *recvFrom; sendToFunc *sendTo; #ifdef FULLMETHOD /* These are currently unused, since the method negotiation is responsible for changing them. */ inboundFunc *inbound; outputFunc *output; recvFunc *recv; /* defaults to recv() */ sendFunc *send; /* defaults to send() */ excpFunc *excp; /* defaults to nullExcp() */ #endif }; struct intMethInfo { char *name; infoFunc *info; }; struct clientMethodInfo { hostLType src; /* for these sources */ mInPLType methods; }; #define ACTION_PERMIT 1 #define ACTION_PERMIT_OK 2 #define ACTION_DENY 3 #define ACTION_SKIP 4 /* skip the next rule */ struct clientInfo { int action; int request; /* one of SOCKS5_CONNECT and friends */ strLType users; hostLType src,dest; portLType port; char *cmd; int timeOut; int bufSize; int flags; }; struct configInfo { daemonInfoType daemon; logInfoType log; defaultInfoType defaults; rtInLType routes; clInLType clients; mInfLType methods; cmInLType cliMeth; strLType env; /* global environment */ }; #include "logging.h" /* dns.c */ extern fdInfoType *dnsInfo; void dnsGlobalInit(void); void dnsServerInit(void); inboundUdpFunc dnsInboundUdp; struct hostent *dnsQuery(char *name, fdInfoType *client); void dnsDestroy(void); /* gram.y */ void defaultConfig(void); extern configInfoType newConfig, config; void freeConfig(configInfoType *cfg); int strToFacility(char *name); char *facilityToStr(int facil); methodInfoType *findMethod(configInfoType *cfg,char *name); /* internal.c */ extern intMethInfoType intMethods[]; int loadMethInfo(methodInfoType *mInfo); /* lexer.l */ char *timeToStr(int time); char *expandString(const char *us); /* listen.c */ extern int listenTries; extern struct timeval lastAccept; extern int avgClientTime; extern float avgClientWeight; recvFunc listenRecv; inboundFunc newClient; void tryListen(int lock); void unListen(int forever); void checkPidLock(int nSlot); /* logging.c */ void logStartup(fdInfoType *info); void logClose(fdInfoType *info, u_int32_t reason); logRecType *makeLogRec(fdInfoType *info, u_int32_t reason); /* methods.c */ int loadMethInfo(methodInfoType *mInfo); methodInfoType *findMatchingMethod(struct sockaddr_in *sin,u_char *methData); /* signal.c */ void doSignals(void); #ifdef __hpux void markSignal(int sig, int code, struct sigcontext *scp); #else void markSignal(int sig); #endif extern volatile int pendingSig; /* sockd.c */ extern configInfoType config; extern pid_t processGroup; extern fdInfoType *fdInfo; extern connInfoType *freeConn; extern connInfoType *connInfo; extern int maxConn; extern int maxFd; extern volatile int highFd,lowFd; extern int *daemonFd; extern negotPageType *negot; /* negotiation page */ extern volatile int negotSlot; extern negotInfoType *negotInfo; extern int debug; extern volatile int pendingTerm; /* term signal is pending */ extern time_t now; /* time at select loop start. */ #define DBG_FOREGROUND 1 #define DBG_MAINLOOP 2 #define DBG_CLOSE 0x10 #define DBG_CHILD 0x40 #define DBG_DNS 0x80 #define DBG_TRAIL 0x100 #define DBG_UNLISTEN 0x200 #define DBG_VALIDATE 0x400 #define DBG_SANITY 0x800 extern int logFd; void nullExcp(fdInfoType *info); void dumpConfig(int sig); void terminate(int sig); void readConfig(int sig); void setupSignals(int daemon); /* util.c */ void freeSomeMemory(dataBufType *buf); extern negotInfoType loserInfo; /* negotInfo structure for non-listeners */ void bufFree(dataBufType *inf); void addToBuffer(fdInfoType *info,dataBufType *inf,void *buf,int len); int getFromBuffer(void *buf,dataBufType *inf,int len,int peek); void setupTimeouts(connInfoType *conn,int timeout); void setSocketBuffer(int fd, int bufSize); void pendingClose(fdInfoType *info,int why); void connSanity(int call); void closeConnection(fdInfoType *info,int why,int closeNow); int createSocket(int af, int type, int protocol); void setSelect(int fd,int which); void clrSelect(int fd,int which); #define SL_READ 1 #define SL_WRITE 2 #define SL_EXCP 4 #define SL_ALL (SL_READ|SL_WRITE|SL_EXCP) void setupDaemon(int numConn); void forgetInfo(fdInfoType *info); int spawnChild(connInfoType *conn); void destroyDaemon(void); void negotLock(void); void negotUnlock(void); int compareAddr(hostType *host, u_int32_t IP); u_int32_t findRoute(u_int32_t destIP); void addTimeOut(fdInfoType *info); void reQueueTimeOut(fdInfoType *info); const char *getEnv(const fdInfoType *info,const char *name); u_int32_t inetAddr(const char *s); void footprint(u_short a, u_short b, int c, int d); void dumpFootprint(int where); void setCommandLine(char *s); /* v4.c */ inboundFunc newV4Client; infoFunc v4Info; extern methodInfoType *v4Method; /* for v4 emulation */ /* v5.c */ inboundFunc newV5Client; infoFunc noAuthInfo; outputFunc v5Request; void v5WriteReply(fdInfoType *client, struct sockaddr_in *sin, int result, int flags); /* v5command.c */ void doCommand(const char *cmd,fdInfoType *info); /* fork and execute a command */ void doCommand2(const char *cmd,fdInfoType *client); int v5DoCommand(fdInfoType *client,const char *name); /* v5tcp.c */ inboundFunc simpleInbound; outputFunc simpleOutput; sendFunc v5ConnectSendReply; recvFunc v5BindRecv; int v5DoConnect(fdInfoType *client); int v5DoBind(fdInfoType *client); /* v5udp.c */ inboundUdpFunc simpleInboundUdp; outputUdpFunc simpleOutputUdp; int v5DoUdpAssociate(fdInfoType *client); inboundUdpFunc v5InboundUdpReq; /* UDP request from client */ outputUdpFunc v5OutputUdpReply; /* UDP reply to client */ /* userpass.c */ infoFunc userPassInfo; #endif /* SOCKD_H_INCLUDED */ hpsockd-0.17build2/src/sockd/usage.c0000644000000000000000000003606011024757214014236 0ustar /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __lint static char sccsid[]="@(#)$Header: /var/cvs/hpsockd/src/sockd/usage.c,v 0.15 2003/01/19 14:05:56 lamont Exp $"; static char *copyright="@(#)Copyright Hewlett-Packard Company, 1997-2000."; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "btree.h" #include #include "logging.h" #define STRCASEEQ(a, b) (strcasecmp(a, b) == 0) #define STREQ(a, b) (strcmp(a, b) == 0) #define Max(a,b) ((a)<(b) ? (b) : (a)) #define NEW(x) ((x*)malloc(sizeof(x))) #define CNEW(n,x) ((x*)calloc((n),sizeof(x))) #ifdef NO_LONG_LONG typedef struct { long h; long l; } llType; #define ADD(res,p1,p2) ((res).h=(p1).h+(p2).h,((res).l=(p1).l+(p2).l)>=1000000000 ? (res).h++,(res).l-=1000000000 : 0) #define ADDL(res,p1,p2) ((res).h=(p1).h,((res).l=(p1).l+(p2))>=1000000000 ? (res).h++,(res).l-=1000000000 : 0) #define ZERO(res) ((res).h=(res).l=0) #else /* !NO_LONG_LONG */ typedef long long llType; #define ADD(res,p1,p2) ((res)=(p1)+(p2)) #define ADDL(res,p1,p2) ((res)=(p1)+(p2)) #define ZERO(res) ((res)=0) #endif /* !NO_LONG_LONG */ typedef struct Conn ConnType; typedef enum { protoTcp,protoUdp} protoType; typedef enum { bindCmd=LG_TYPE_BIND,connectCmd=LG_TYPE_CONNECT,udpAssocCmd=LG_TYPE_UDPASSOC } typeType; #ifndef __lint char *typeName[] = { "Bind","Cnct","UdpAssoc" }; char *protoName[] = { "TCP", "UDP" }; #endif #define MAXCHASH 64 #define CKEY(id) ((id)%MAXCHASH) typedef struct { u_char *dest; unsigned short port; protoType proto; } DkeyType; typedef struct { DkeyType *key; llType recvd; llType sent; long count; } DdataType; typedef struct { u_char *src; char *user; } SkeyType; typedef struct { SkeyType *key; llType recvd; llType sent; long count; } SdataType; struct Conn { ConnType *link; logHeadType head; SdataType *src; DdataType *dst; } *Chash[MAXCHASH]; void *Droot=NULL,*Sroot=NULL; long debug=0; #define DBG_INPUT 0x1000 #define DBG_DUMP 0x2000 #define DBG_SVALID 0x10000 #define DBG_DVALID 0x20000 int show_source; int show_dest; int verbose; unsigned int host; /* one host only */ int main (int argc, char **argv); int process_file (FILE *in); void lostConn(ConnType *conn); ConnType *findConn(long id); void freeConn(ConnType *conn); SdataType *addSrc(u_char *src,char *srcusr); DdataType *addDst(u_char *dst,unsigned short dstport, protoType proto); void outputStats(void); int Sprint(void *key, void *data,btw_t which,void*info); int Dprint(void *key, void *data,btw_t which,void*info); int Scmp(void *uk1, void *uk2); int Dcmp(void *uk1, void *uk2); char *address(u_char *addr); const char *lltos(llType ll) { static char buf[80]; static char which=1; register char *c,*c1; register long a,b,l; #ifndef NO_LONG_LONG register llType aa; #endif which^=1; c1=c=buf+which*40; #ifdef NO_LONG_LONG while (ll.l >= 1000000000) { ll.l -= 1000000000; ll.h++; } l=ll.l; a=ll.h; b=0; #else /* !NO_LONG_LONG */ aa=ll/1000000000; b=aa/1000000000; /* 10^18 and up */ a=aa%1000000000; /* 10^17..10^9 */ l=ll%1000000000; /* 10^8..10^0 */ #endif /* !NO_LONG_LONG */ *c='\0'; if (b) sprintf(c,"%d",b); if (a||b) sprintf(c+strlen(c),b?"%09d":"%d",a); sprintf(c+strlen(c),(a||b)?"%09d":"%d",l); return c1; } const char *ntoa(unsigned long ip) { struct in_addr ia; ia.s_addr=ip; return inet_ntoa(ia); } int main(int argc, char **argv) { int c; char *myname; FILE *in; extern char *optarg; extern int optind; int status=0; myname=strrchr(argv[0],'/'); if (myname==NULL) myname=argv[0]; else myname++; while ((c=getopt(argc,argv,"D:sdvn:h:")) != EOF) switch (c) { case 'D': debug=strtol(optarg,(char**)NULL,0); break; case 's': show_source=1; break; case 'd': show_dest=1; break; case 'v': verbose++; break; case 'h': host=inet_addr(optarg); break; case ':': case '?': fprintf(stderr, "Usage: %s [-sdvv] [-n name] [-h host] [file...]\n", myname); exit(1); } if (!show_source && !show_dest) show_source++; if (optind==argc) { if (process_file(stdin)<0) status=2; } else for (;optind= LG_TYPE_CLIENT && logHead.type < LG_TYPE_CLIENT+256) { register u_char *src,*utmp,*dest,*p; register u_short dstport; char user[256]; register SdataType *srcData; register DdataType *dstData; register unsigned int toSrc, toDest; logHead.type-=LG_TYPE_CLIENT; src=(void*)(buf+sizeof(unsigned int)); /* skip elapsed time */ utmp=src+ADDRLEN(src); dest=utmp+*utmp+1; if (host) { if (*src==ATYP_V4 && *dest==ATYP_V4) { if (memcmp(src+1,&host,sizeof(host))!=0 && memcmp(dest+1,&host,sizeof(host))!=0) continue; /* next record */ } } p=dest+ADDRLEN(dest); dstport=((crunchType*)p)->us; p+=sizeof(short)+1; /* skip method */ toSrc=((crunchType*)p)->ui; p+=sizeof(unsigned int); toDest=((crunchType*)p)->ui; p+=sizeof(unsigned int); user[*utmp]='\0'; memcpy(user,utmp+1,*utmp); srcData=addSrc(src,user); srcData->count++; dstData=addDst(dest,dstport,(logHead.type==LG_TYPE_UDPASSOC) ? protoUdp : protoTcp); dstData->count++; ADDL(srcData->recvd,srcData->recvd,toDest); ADDL(dstData->sent,dstData->sent,toDest); ADDL(dstData->recvd,dstData->recvd,toSrc); ADDL(srcData->sent,srcData->sent,toSrc); } else switch(logHead.type) { case LG_TYPE_CONNECT: case LG_TYPE_BIND: case LG_TYPE_UDPASSOC: /* Not in the old files, but hey, why not. */ case LG_TYPE_PING: /* Not in the old files, but hey, why not. */ case LG_TYPE_TRACEROUTE: /* Not in the old files, but hey, why not. */ { register u_char *src,*utmp,*dest; register u_short dstport; register ConnType *conn; char user[256]; src=(void*)buf; utmp=src+ADDRLEN(src); dest=utmp+*utmp+1; dstport=((crunchType*)(dest+ADDRLEN(dest)))->us; user[*utmp]='\0'; memcpy(user,utmp+1,*utmp); if ((conn=findConn(id)) != NULL) { lostConn(conn); freeConn(conn); } conn=NEW(ConnType); conn->head=logHead; conn->src=addSrc(src,user); conn->src->count++; conn->dst=addDst(dest,dstport,(logHead.type==LG_TYPE_UDPASSOC) ? protoUdp : protoTcp); conn->dst->count++; conn->link=Chash[CKEY(id)]; Chash[CKEY(id)]=conn; } break; case LG_TYPE_CLOSE: { register ConnType *conn; register SdataType *src; register DdataType *dst; register logCloseType *logClose=(logCloseType*)dbuf; if ((conn=findConn(id))==NULL) { static u_char unkHost[]={ ATYP_DOMAIN,9,'.','u','n','k','n','o','w','n','.' }; static char *unkUser="\010|unknown"; fprintf(stderr,"Orphan close 0x%08x\n",id); src=addSrc(unkHost,unkUser); dst=addDst(unkHost,0,protoTcp); } else { src=conn->src; dst=conn->dst; } ADDL(src->recvd,src->recvd,logClose->toDest); ADDL(dst->sent,dst->sent,logClose->toDest); ADDL(dst->recvd,dst->recvd,logClose->toSrc); ADDL(src->sent,src->sent,logClose->toSrc); if (conn) { freeConn(conn); } } break; default: fprintf(stderr,"Unknown log record type %d\n",logHead.type); continue; } } return 0; } void lostConn(ConnType *conn) { fprintf(stderr,"Lost connection 0x%08x\n",conn->head.id); /* XXX - finish lostConn */ } ConnType *findConn(long id) { register ConnType *conn=Chash[CKEY(id)]; while (conn && (conn->head.id != id)) conn=conn->link; return conn; } void freeConn(ConnType *conn) { register long key=CKEY(conn->head.id); register ConnType *prev=Chash[key]; if (prev==conn) { Chash[key]=conn->link; } else { while (prev && prev->link != conn) prev=prev->link; if (!prev) { fprintf(stderr,"Freeing free connection\n"); return; } prev->link=conn->link; } free(conn); } #if 0 void freeSrc(SdataType *src) { register int key=SKEY(src->key->ip); register SdataType *prev=S_hash[key]; if (prev==src) { S_hash[key]=src->link; } else { while (prev && prev->link != src) prev=prev->link; if (!prev) { fprintf(stderr,"Freeing free source\n"); return; } prev->link=src->link; } free(src->key->src); free(src->key->user); free(src); } void freeDst(DdataType *dst) { register int key=DKEY(dst->key->ip); register DdataType *prev=D_hash[key]; if (prev==dst) { D_hash[key]=dst->link; } else { while (prev && prev->link != dst) prev=prev->link; if (!prev) { fprintf(stderr,"Freeing free destination\n"); return; } prev->link=dst->link; } free(dst->key->dest); free(dst); } #endif SdataType *addSrc(unsigned char *src,char *user) { register SkeyType *key=NEW(SkeyType); register SdataType *data=CNEW(1,SdataType),*ret; key->src=malloc(ADDRLEN(src)); memcpy(key->src,src,ADDRLEN(src)); key->user=strdup(user); data->key=key; ret=(SdataType *)btsearch(&Sroot,key,data,Scmp,BT_INS); if (ret != data) { assert(memcmp(key->src,ret->key->src,ADDRLEN(src))==0 && strcmp(key->user,ret->key->user)==0); free(key->src); free(key->user); free(key); free(data); } if (debug&DBG_SVALID) assert(btvalidate(Sroot,Scmp)==0); return ret; } DdataType *addDst(u_char *dst,unsigned short dstport,protoType proto) { register DkeyType *key=NEW(DkeyType); register DdataType *data=CNEW(1,DdataType),*ret; key->dest=malloc(ADDRLEN(dst)); memcpy(key->dest,dst,ADDRLEN(dst)); key->port=dstport; key->proto=proto; data->key=key; ret=(DdataType *)btsearch(&Droot,key,data,Dcmp,BT_INS); if (ret != data) { assert(memcmp(key->dest,ret->key->dest,ADDRLEN(dst))==0 && key->port==ret->key->port && key->proto==ret->key->proto); free(key->dest); free(key); free(data); } if (debug&DBG_DVALID) assert(btvalidate(Droot,Dcmp)==0); return ret; } void outputStats(void) { register int i; /* any outstanding connections? */ for (i=0; i< MAXCHASH;i++) { register ConnType *conn=Chash[i]; while (conn != NULL) { register ConnType *save=conn->link; lostConn(conn); freeConn(conn); conn=save; } } /* now do the source data */ if (show_source) btwalk(Sroot,Sprint,NULL); if (show_dest) btwalk(Droot,Dprint,NULL); } static llType gin,gout; static long gcnt; static llType tin,tout; static long tcnt; int Sprint(void *ukey, void *udata,btw_t which,void*info) { register SkeyType *key=(SkeyType*)ukey; register SdataType *data=(SdataType*)udata; static SkeyType *lastkey=NULL; if (which == bt_first) { ZERO(tin); ZERO(tout); tcnt=0; ZERO(gin); ZERO(gout); gcnt=0; return 0; } if (which == bt_last || lastkey != NULL && memcmp(lastkey->src,key->src,ADDRLEN(key->src))!=0) { if (verbose) printf("ST:%s:%s:%s:%d\n",address(lastkey->src),lltos(tout),lltos(tin),tcnt); ADD(gin,gin,tin); ADD(gout,gout,tout); gcnt+=tcnt; ZERO(tin); ZERO(tout); tcnt=0; } if (which == bt_last) { printf("SG:%s:%s:%d\n", lltos(gout), lltos(gin),gcnt); return 0; } if (verbose > 1) { printf("SD:%s:%s:%s:%s:%d\n",address(key->src),key->user, lltos(data->sent),lltos(data->recvd),data->count); } ADD(tin,tin,data->recvd); ADD(tout,tout,data->sent); tcnt+=data->count; lastkey=key; return 0; } int Scmp(void *uk1, void *uk2) { register SkeyType *k1=(SkeyType*)uk1,*k2=(SkeyType*)uk2; register int i; if (i=memcmp(k1->src,k2->src,ADDRLEN(k1->src))) return i; else return (i=*k1->user-*k2->user)?i:strcmp(k1->user+1,k2->user+1); } int Dprint(void *ukey, void *udata,btw_t which,void*info) { register DkeyType *key=(DkeyType*)ukey; register DdataType *data=(DdataType*)udata; static DkeyType *lastkey=NULL; if (which == bt_first) { ZERO(tin); ZERO(tout); tcnt=0; ZERO(gin); ZERO(gout); gcnt=0; return 0; } if (which == bt_last || lastkey != NULL && memcmp(lastkey->dest,key->dest,ADDRLEN(key->dest))!=0) { if (verbose) printf("DT:%s:%s:%s:%d\n",address(lastkey->dest),lltos(tout),lltos(tin),tcnt); ADD(gin,gin,tin); ADD(gout,gout,tout); gcnt+=tcnt; ZERO(tin); ZERO(tout); tcnt=0; } if (which == bt_last) { printf("DG:%s:%s:%d\n", lltos(gout), lltos(gin),gcnt); return 0; } if (verbose > 1) { printf("DD:%s:%d:%s:%s:%s:%d\n",address(key->dest),key->port,protoName[key->proto], lltos(data->sent),lltos(data->recvd),data->count); } ADD(tin,tin,data->recvd); ADD(tout,tout,data->sent); tcnt+=data->count; lastkey=key; return 0; } int Dcmp(void *uk1, void *uk2) { register DkeyType *k1=(DkeyType*)uk1,*k2=(DkeyType*)uk2; register int i; if (i=memcmp(k1->dest,k2->dest,ADDRLEN(k1->dest))) return i; else return (i=k1->port-k2->port) ? i : k1->proto-k2->proto; } char *address(u_char *addr) { static char buf[256]; struct in_addr in; switch(*addr) { case ATYP_V4: memcpy(&in,addr+1,4); return inet_ntoa(in); case ATYP_V6: sprintf(buf,"v6 addr"); /* XXX */ break; case ATYP_DOMAIN: addr++; buf[*addr]='\0'; memcpy(buf,addr+1,*addr); break; default: sprintf(buf,"unknown_address_type %d",*addr); break; }; return buf; } hpsockd-0.17build2/src/sockd/listen.c0000644000000000000000000003171211024757214014427 0ustar #include "sockd.h" #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/listen.c,v 0.51 2002/01/28 18:15:12 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ void tryListenLock(void); int listenTries=10; struct timeval lastAccept; int avgClientTime; float avgClientWeight=0.99; #define LISTEN_FAIL -1 #define LISTEN_NOONE -2 #define LISTEN_GOTONE -3 /**************************************************************************** * * listenRecv() is the recv function for the listen socket. His job is to * accept new connections (since there are multiple listners, just getting * a read select doesn't mean you'll get a connection, so deal with EWOULDBLOCK) * * After accepting the new connection, we create a socket for the peer side * of things. If we've hit the connection limit, then we fork and the child * gets all of the connections. * ****************************************************************************/ /* returns -2 (all OK), or -1 (drop the connection) */ /* recvFunc */ /* ARGSUSED */ ssize_t listenRecv1(int fd, void *buf,size_t count,unsigned int flags) { struct sockaddr_in sin; int len=sizeof(sin); register int newFd; register fdInfoType *client,*peer; register int peerFd=-1; register connInfoType *conn; int val; struct timeval myTime; if (avgClientTimenumConn; syslog(LOG_WARNING,"Got EMFILE at %d connections", negotInfo->numConn); if (spawnChild(NULL)) { continue; } else { return LISTEN_NOONE; } } if (errno==ENOBUFS) { syslog(LOG_WARNING,"Got ENOBUFS on accept"); if (debug&DBG_SANITY) dumpFootprint(-1); return LISTEN_NOONE; } return LISTEN_FAIL; } } while (newFd<0); bumpHighLow(newFd); gettimeofday(&myTime,(struct timezone*)NULL); avgClientTime=(int)((float)avgClientTime*avgClientWeight+ (1.0-avgClientWeight)*((myTime.tv_sec-lastAccept.tv_sec)*1000+ (myTime.tv_usec-lastAccept.tv_usec)/1000)); lastAccept=myTime; val=((config.daemon.flags&FL_NO_KEEPALIVE)==0); if (setsockopt(newFd,SOL_SOCKET,SO_KEEPALIVE,&val,sizeof(val))<0) syslog(LOG_NOTICE,"setsockopt(SO_KEEPALIVE) failed %m"); val=1; if (setsockopt(newFd,SOL_SOCKET,SO_OOBINLINE,&val,sizeof(val))<0) syslog(LOG_NOTICE,"setsockopt(SO_OOBINLINE) failed %m"); setNonBlocking(newFd); do { peerFd=createSocket(AF_INET,SOCK_STREAM,0); if (peerFd<0) { if (errno==EMFILE) { config.daemon.maxClient=negotInfo->numConn; syslog(LOG_WARNING,"Got EMFILE at %d connections", negotInfo->numConn); if (spawnChild(NULL)) { continue; } else { close(newFd); return LISTEN_NOONE; } } close(newFd); return LISTEN_FAIL; } } while (peerFd<0); bumpHighLow(peerFd); if (newFd>=maxFd || peerFd>=maxFd) { config.daemon.maxClient=negotInfo->numConn; syslog(LOG_WARNING,"Got EMFILE at %d connections", negotInfo->numConn); if (spawnChild(NULL)) { register int t1,t2; t1=dup(newFd); close(newFd); t2=dup(peerFd); close(peerFd); if (t1<0 || t2<0) { if (t1>=0) close(t1); if (t2>=0) close(t2); syslog(LOG_ERR,"Unable to recover from spawning child: %m"); return LISTEN_FAIL; } newFd=t1; peerFd=t2; if (newFd>=maxFd || peerFd>=maxFd) { syslog(LOG_ERR,"Too many file descriptors"); close(newFd); close(peerFd); unListen(1); return LISTEN_NOONE; } } else { close(newFd); close(peerFd); return LISTEN_NOONE; } } if (config.daemon.inetdSecFile && DoInetdSec(config.daemon.service,&sin,config.daemon.inetdSecFile)<0) { syslog(LOG_ERR,"Connection denied (inetd.sec) for %s",inet_ntoa(sin.sin_addr)); close(newFd); close(peerFd); return LISTEN_GOTONE; } /* Do we need another daemon? */ if (negotInfo->numConn >= config.daemon.maxClient) { if(!spawnChild(NULL)) { close(newFd); close(peerFd); return LISTEN_NOONE; } } negotInfo->numConn++; footprint(2,newFd,peerFd,0); connSanity(2); client=fdInfo+newFd; peer=fdInfo+peerFd; /* We should never get here with freeConn==NULL */ conn=freeConn; freeConn=(connInfoType*)conn->client; if (conn->flags&CO_IN_USE) { syslog(LOG_ERR,"structure insanity: connection in use"); abort(); } memset(client,0,sizeof(*client)); memset(peer,0,sizeof(*peer)); memset(conn,0,sizeof(*conn)); client->fd=newFd, peer->fd=peerFd; client->conn=peer->conn=conn; client->sin=sin; conn->client=client; conn->flags|=CO_IN_USE; client->flags=FD_IS_CLIENT; peer->TCP_RECV=client->TCP_RECV=(recvFunc*)recv, peer->TCP_SEND=client->TCP_SEND=(sendFunc*)send; peer->excp=client->excp=nullExcp; conn->bufSize=config.defaults.bufSize; client->TCP_INBOUND=newClient, client->TCP_OUTPUT=simpleOutput; peer->TCP_INBOUND=simpleInbound, peer->TCP_OUTPUT=v5Request; setSelect(newFd,SL_READ|SL_EXCP); peer->peer=client, client->peer=peer; /* sets startTime, timeOut, and expire */ setupTimeouts(conn, config.defaults.setupTimeOut ? config.defaults.setupTimeOut : config.defaults.timeOut); return LISTEN_GOTONE; } ssize_t listenRecv(int fd, void *buf,size_t count,unsigned int flags) { register int i; register ssize_t ret=LISTEN_GOTONE; for (i=listenTries; i>0 && ret==LISTEN_GOTONE; i--) { ret=listenRecv1(fd,buf,count,flags); } } /**************************************************************************** * * newClient() is the initial inbound function for a client. Once we get * enough data (one byte) to tell which protocol we're talking, we go to * the version specific new client code. If we get a bogus version, just * drop the connection. * ****************************************************************************/ /* inboundFunc */ void newClient(fdInfoType *client,void *buf,int len,unsigned int flags) { /* make sure we have enought data to proceed - buffer it */ addToBuffer(client,&client->in,buf,len); if (client->in.dataLen<1) return; switch (*client->in.dataStart) { case SOCKS_V4: /* V4 emulation */ client->TCP_INBOUND=newV4Client; newV4Client(client,NULL,0,flags); break; case SOCKS_V5: /* V5 */ if (!(config.daemon.flags&FL_V4_ONLY)) { client->TCP_INBOUND=newV5Client; newV5Client(client,NULL,0,flags); break; } /* fall through */ default: syslog(LOG_WARNING,"Bad version %d from %s", *client->in.dataStart,inet_ntoa(client->sin.sin_addr)); pendingClose(client,LOG_PROTOCOL_ERROR); break; } } /***************************************************************************** * * Now we get into the listen negotiation code. Routines ending in Lock are * only called with the negotLock() held. * * checkPidLock() makes sure that the pid in the slot is still alive, and * assumes that the pid is non-zero. * *****************************************************************************/ void checkPidLock(int nSlot) { register negotInfoType *nInfo=negot->slot+nSlot; register int ret; /* assumes negotLock() active. */ ret=kill(nInfo->pid,0); if (ret<0) { syslog(LOG_WARNING,"Detected death of pid %d: %m",nInfo->pid); nInfo->pid=0; if (LI_ISSET(nSlot,negot->head.listeners)) { LI_CLR(nSlot,negot->head.listeners); negot->head.numListen--; } } } void doListenLock(void) { register int i; /* Assumes that negotLock() is active */ if (!LI_ISSET(negotSlot,negot->head.listeners)) { LI_SET(negotSlot,negot->head.listeners); negot->head.numListen++; } for (i=0;daemonFd[i]>=0; i++) { setSelect(daemonFd[i],SL_READ); } } void unListenLock(void) { register int i; /* Assumes that negotLock() is active */ if (LI_ISSET(negotSlot,negot->head.listeners)) { LI_CLR(negotSlot,negot->head.listeners); negot->head.numListen--; } for (i=0;daemonFd[i]>=0; i++) { clrSelect(daemonFd[i],SL_READ); } } void unListen(int forever) { #ifdef __hpux int *ap=&forever; #endif if (negotInfo==&loserInfo) return; if (forever || (debug&DBG_UNLISTEN)) { #ifdef __hpux syslog(LOG_NOTICE,"unListen(%d) from 0x%x",forever,ap[4]); #else syslog(LOG_NOTICE,"unListen(%d)",forever); #endif } negotLock(); if (forever && (negotInfo->flags&NF_LOSER)) { /* vacate the table entry */ loserInfo=*negotInfo; negotInfo->pid=0; negotInfo=&loserInfo; negotUnlock(); return; } unListenLock(); if (forever) { char cmdLine[256]; negotInfo->flags|=NF_LOSER; snprintf(cmdLine,sizeof(cmdLine),"%s --nolisten",config.daemon.name); setCommandLine(cmdLine); } negotUnlock(); if (forever) { register int i; for (i=0;daemonFd[i]>=0; i++) { close(daemonFd[i]); fdInfo[daemonFd[i]].fd=-1; daemonFd[i]=-1; } if (!negotInfo->numConn) destroyDaemon(); } } typedef struct sort sortType; struct sort { u_short score; u_short idx; }; void tryListen(int lock) { if (negotInfo->flags&NF_LOSER) return; if (!lock) negotLock(); tryListenLock(); if (!lock) negotUnlock(); } void tryListenLock(void) { register int betterListen=0; register negotInfoType *nInfo; register int numConn=negotInfo->numConn; register int minListen=config.daemon.minListen; #ifdef USE_SIGNALS sortType sort[NEGOT_MAXSLOT+1]; register int numDaemon=0; #endif /* USE_SIGNALS */ register int i; negotInfo->lastChecked=now; /* Handle the no brainer cases first: not enough clients, or too many clients */ if (numConn < config.daemon.minClient) { doListenLock(); return; } else if (numConn >= config.daemon.maxClient) { unListenLock(); return; } /* figure out how many potential listeners there are, and set things up for the kinda-sort. */ for (i=0,nInfo=negot->slot;ipid && nInfo->lastChecked+5lastChecked=now; } if (!nInfo->pid || (nInfo->flags&NF_LOSER)) continue; #ifdef USE_SIGNALS sort[numDaemon].score=nInfo->numConn; sort[numDaemon].idx=i; numDaemon++; #else /* ! USE_SIGNALS */ if (nInfo->numConnminListen) { register int a,z,i,j,k; /* lots of places below walk off the end of the world if we don't do this */ sort[numDaemon].score=config.daemon.maxClient+99; sort[numDaemon].idx=-1; numDaemon++; a=i=0; z=j=numDaemon-1; do { k=sort[i++].score; while (i= sort[i].score) i++; while (k < sort[j].score) j--; if (i minListen) i=a,j=z=j-1; else if (j+1 < minListen) a=i=j+1,j=z; } while (j+1!=minListen && a < minListen); k=sort[j++].score; while (k==sort[j].score) j++; /* at this point, j points to the first non-listner entry in the table. */ if (numConn < sort[j].score) doListenLock(); else unListenLock(); for (i=0;ihead.listeners) || i >=j && LI_ISSET(i,negot->head.listeners)) { ret=kill(negot->slot[sort[i].idx].pid,SIGWAKEUP); } } } else { doListenLock(); } #else /* ! USE_SIGNALS */ if (betterListenhead.numListen) doListenLock(); #endif /* ! USE_SIGNALS */ } hpsockd-0.17build2/src/sockd/logging.c0000644000000000000000000001233511024757214014557 0ustar #include "sockd.h" #include "v5.h" #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/sockd/logging.c,v 0.26 2001/03/02 01:34:54 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ static u_short nextId=1; static pid_t myPid; #define ADDRLEN(a) (*(a)==ATYP_V4 ? 5 : *(a)==ATYP_V6 ? 17 : 2+*(a+1)) int logFd=-1; time_t lastLogOpen=0; /* ARGSUSED */ void newLog(int sig) { myPid=getpid(); if (!config.log.level) return; if (logFd>=0) { close(logFd); } logFd=open(config.log.logFile,O_WRONLY|O_APPEND); if (logFd<0) { logFd=open(config.log.logFile,O_WRONLY|O_APPEND|O_CREAT|O_EXCL,0644); close(logFd); logFd=open(config.log.logFile,O_WRONLY|O_APPEND); } if (logFd<0) { syslog(LOG_ERR,"Unable to open log file %s: %m. Turning off logging.",config.log.logFile); config.log.level=0; return; } lastLogOpen=time((time_t*)NULL); } void logStartup(fdInfoType *info) { register connInfoType *conn=info->conn; if (config.log.level < LG_STATS) return; if (!conn->startTime) conn->startTime=now; if (!conn->logId) conn->logId=htonl(((myPid<<16)|((nextId++)&0xffff))); return; } logRecType *makeLogRec(fdInfoType *info, u_int32_t reason) { register int i; register connInfoType *conn=info->conn; register fdInfoType *udp=conn->udp; register int id=conn->logId; static logRecType rec; register char *p=(char*)rec.chars; v5HeadType *req=conn->req; register struct sockaddr_in *srcSin=&info->sin, *destSin=&info->peer->sin; u_int32_t tmp; if (req==NULL && conn->error != LOG_NOMETHOD) { syslog(LOG_CRIT,"makeLogRec got null request pointer. Info=%08x flags=%08x pid=%d",info,info->flags,conn->pid); /* XXX */ return NULL; } rec.head.type=LG_TYPE_CLIENT+req->cmd; rec.head.time=htonl(now); rec.head.id=htonl(id); tmp=htonl(now-conn->startTime); memcpy(p,&tmp,sizeof(tmp)); p+=sizeof(tmp); switch(srcSin->sin_family) { case AF_INET: *p=ATYP_V4; memcpy(p+1,&srcSin->sin_addr,4); p+=5; break; #ifdef AF_INET6 case AF_INET6: *p=ATYP_V6; memcpy(p+1,&srcSin->sin_addr,16); p+=17; break; #endif default: syslog(LOG_WARNING,"got source address family %d in makeLogRec",srcSin->sin_family); return NULL; /* Beats me what it is... */ } if (conn->user) { i=strlen(conn->user)&0xff; *p++=i; memcpy(p,conn->user,i); p+=i; /* name limited to 255 octets */ } else { *p++=0; } switch(destSin->sin_family) { register u_char *c; default: c=(u_char*)&destSin->sin_addr; if (destSin->sin_family || destSin->sin_port || c[0] || c[1] || c[2] || c[3]) { syslog(LOG_WARNING,"got destination address family %d in makeLogRec",destSin->sin_family); /* Beats me what it is, lets pretend it's v4... */ } /* fall through */ case AF_INET: *p=ATYP_V4; memcpy(p+1,&destSin->sin_addr,4); p+=5; break; #ifdef AF_INET6 case AF_INET6: *p=ATYP_V6; memcpy(p+1,&destSin->sin_addr,16); p+=17; break; #endif } memcpy(p,&destSin->sin_port,sizeof(u_short)); p+=sizeof(u_short); *p++=conn->method->num; tmp=htonl(info->out.totalBytes + (udp ? udp->out.totalBytes : 0)); memcpy(p,&tmp,sizeof(tmp)), p+=sizeof(tmp); tmp=htonl(info->peer->out.totalBytes + (udp ? udp->peer->out.totalBytes : 0)); memcpy(p,&tmp,sizeof(tmp)), p+=sizeof(tmp); tmp=htonl(reason); memcpy(p,&tmp,sizeof(tmp)), p+=sizeof(tmp); tmp=p-(char*)&rec; rec.head.size=htons(tmp); return &rec; } void logClose(fdInfoType *info, u_int32_t reason) { register logRecType *rec; register int i,ret; register connInfoType *conn=info->conn; now=time((time_t*)NULL); if (conn==NULL) { syslog(LOG_ERR,"Null connection pointer in logClose"); #ifdef __hpux dumpMap(0); #endif return; } if (config.log.level < LG_STATS || !conn->logId) return; /* Horrible kludge to allow the log file to move out from under us without needing a signal. * This is because only the current process group gets signaled by sdc. With this kludge, * we'll start writing to the new log file withine 60 seconds of it getting created... */ if (lastLogOpen+60 < now) { i=open(config.log.logFile,O_WRONLY|O_APPEND); if (i>=0) { ret=dup2(i,logFd); if (ret>=0) { (void)close(i); } else { (void)close(logFd); logFd=i; } } lastLogOpen=now; } rec=makeLogRec(info,reason); conn->logId=0; ret=write(logFd,rec,ntohs(rec->head.size)); if (ret<0) { syslog(LOG_ERR,"Error on logfile write: %m"); } else if (ret != ntohs(rec->head.size)) { syslog(LOG_ERR,"Out of disk space on log file write"); } } hpsockd-0.17build2/src/sockd/v5.h0000644000000000000000000000367611024757214013500 0ustar /* @(#)$Header: /var/cvs/hpsockd/src/sockd/v5.h,v 0.11 2000/12/08 20:47:24 lamont Exp $ */ /* (c) Copyright Hewlett-Packard Company 1997-2000. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef V5_H_INCLUDED #define V5_H_INCLUDED /* command definitions are in logging.h */ typedef struct v5Head v5HeadType; typedef struct v5UdpHead v5UdpHeadType; struct v5Head { u_int8_t version; /* == 5 */ u_int8_t cmd; u_int8_t flags; u_int8_t atyp; u_char destAddr[4]; /* or longer, based on atyp */ /* u_short port; immediately follows destAddr */ }; #define RQ_UDP_USE_CLIENT_PORT 1 #define RQ_UDP_INTERFACE_DATA 4 struct v5UdpHead { u_int16_t rsv; u_int8_t frag; u_int8_t atyp; u_char destAddr[4]; /* or longer, based on atyp */ /* u_short port; immediately follows destAddr */ }; inboundFunc newV5Client; int v5DoConnect(fdInfoType *info); int v5DoBind(fdInfoType *info); int v5DoUdpAssociate(fdInfoType *info); int v5PutSin(const struct sockaddr_in *sin, int sinLen, v5HeadType *reply); int v5GetSin(const v5HeadType *req,struct sockaddr_in *sin,int sinLen); int validate(fdInfoType *info,int flags,v5HeadType **req); /* returns 0 for permit (OK), !=0 for deny. */ #define VL_NONE 0x0000 /* no flags */ #define VL_ISUDPREQ 0x0001 /* this is a udp request */ #endif /* V5_H_INCLUDED */ hpsockd-0.17build2/src/sockd/Makefile0000644000000000000000000000463711024757214014433 0ustar # (c) Copyright Hewlett-Packard Company 1997-2000 # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. include ../Makefile.flags CSRC=methods.c sockd.c util.c logging.c dns.c signal.c MSRC=listen.c v4.c v5.c userpass.c v5command.c v5tcp.c v5udp.c DSRC=sdc.c LSRC=log2ascii.c USRC=usage.c OSRC=lexer.l gram.y HSRC=logging.h sockd.h v4.h v5.h OBJ=methods.o sockd.o signal.o util.o logging.o dns.o gram.tab.o lexer.o vers.o MOBJ=listen.o v4.o v5.o userpass.o v5tcp.o v5udp.o v5command.o DOBJ=sdc.o gram.tab.o lexer.o vers.o LOBJ=log2ascii.o vers.o UOBJ=usage.o vers.o PROGRAMS=sockd sdc log2ascii usage default: opt debug: ../util/libutil.a ${MAKE} `uname -s`.debug opt: ../util/libutil.a ${MAKE} `uname -s` lint: ../util/libutil.a ${MAKE} `uname -s`.lint ../util/libutil.a: @cd ../util; ${MAKE} `uname -s` include ../Makefile.os all: ${PROGRAMS} sockd: ${OBJ} ${MOBJ} ${CC} ${CFLAGS} -o $@ ${OBJ} ${MOBJ} ${CLFLAGS} ../util/libutil.a lintx: ${OBJ} ${MOBJ} lint ${CFLAGS} ${CSRC} ${MSRC} lexer.c gram.tab.c sdc: ${DOBJ} ${CC} ${CFLAGS} -o $@ ${DOBJ} ../util/libutil.a log2ascii: ${LOBJ} ${CC} ${CFLAGS} -o $@ ${LOBJ} ../util/libutil.a usage: ${UOBJ} ${CC} ${CFLAGS} -o $@ ${UOBJ} ../util/libutil.a gram.tab.c gram.tab.h: gram.y if [ -f /usr/bin/byacc ]; then \ byacc -b gram -d -v gram.y; \ else \ yacc -b gram -d -v gram.y; \ fi lexer.c: lexer.l flex -p -s -t lexer.l > lexer.c lexer.o: lexer.c gram.tab.h vers.c: ../../debian/changelog sed -n '1,1s/.*(\(.*\)).*$$/char *socks_version="@(#)sockd version \1";/p' < $? > $@ clean: rm -f *.o gram.output gram.tab.c gram.tab.h lexer.c clobber: clean rm -f ${PROGRAMS} vers.c print: @pr -n $$(echo RCS/*,v | sed 's/RCS.\([^,]*\),v/\1/g') fc: @make debug rsync -ave ssh *.[chyl] sockd ftcona2.hp.com:socks5/ hpsockd-0.17build2/src/Makefile.os0000644000000000000000000000307411024757214013742 0ustar # (c) Copyright Hewlett-Packard Company 1997-2000 # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. HP-UX: ${MAKE} CFLAGS="${HPOPT} ${HPCFLAGS}" CLFLAGS="${HPCLFLAGS} ${HPCLOPTFLAGS}" all HP-UX.debug: ${MAKE} CFLAGS="${HPDEBUG} ${HPCFLAGS}" CLFLAGS="${HPCLFLAGS}" all HP-UX.lint: ${MAKE} CFLAGS="${HPDEBUG} ${HPCFLAGS}" CLFLAGS="${HPCLFLAGS}" lintx HP-UX10: ${MAKE} CFLAGS="${HPOPT} ${HP10CFLAGS}" CLFLAGS="${HP10CLFLAGS} ${HPCLOPTFLAGS}" all HP-UX10.debug: ${MAKE} CFLAGS="${HPDEBUG} ${HP10CFLAGS}" CLFLAGS="${HP10CLFLAGS}" all HP-UX9: ${MAKE} CFLAGS="${HPOPT} ${HP9CFLAGS}" CLFLAGS="${HP9CLFLAGS} ${HPCLOPTFLAGS}" all HP-UX9.debug: ${MAKE} CFLAGS="${HPDEBUG} ${HP9CFLAGS}" CLFLAGS="${HP9CLFLAGS}" all Linux: ${MAKE} CFLAGS="${LINUXOPT} ${LINUXCFLAGS}" CLFLAGS="${LINUXCLFLAGS}" all Linux.debug: ${MAKE} CFLAGS="${LINUXDEBUG} ${LINUXCFLAGS}" CLFLAGS="${LINUXCLFLAGS}" all GNU/kFreeBSD: Linux GNU/kFreeBSD.debug: Linux.debug hpsockd-0.17build2/src/LICENSE0000644000000000000000000004311011024757214012662 0ustar GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. hpsockd-0.17build2/src/Makefile.flags0000644000000000000000000000307411024757214014415 0ustar # (c) Copyright Hewlett-Packard Company 1997-2000 # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #CC=purify -cache-dir=/users/lamont/.purify-cache -follow-child-processes=yes cc COMMON=-I../util -DYYDEBUG=1 HP9CFLAGS=-Ae -z -DHAVE_SHL_LOAD -UHAVE_MMAP ${COMMON} HP9CLFLAGS=-z -Wl,-E -ldld -ldb -lcl HPCFLAGS=-Ae -z -DHAVE_SHL_LOAD -DHAVE_MMAP ${COMMON} #HPCLFLAGS=-z -Wl,-E,-B,immediate -ldld -ldb -lcl -L../util HPCLFLAGS=-z -Wl,-E,-B,immediate -ldld -ldb -lcl -L../util HPCLOPTFLAGS=-u_end_ /opt/langtools/lib/end.o HPDEBUG=-g HPOPT=+DA1.1 +O2 +Olibcalls +ESlit +Ofastaccess +Onolimit #HPOPT=+O1 -g +Olibcalls +ESlit +Ofastaccess +Onolimit #LINUXCFLAGS=-DHAVE_THREADS -DHAVE_DLOPEN -DHAVE_MMAP ${COMMON} #LINUXCLFLAGS=-lpthread -ldl -ldb LINUXCFLAGS=-UHAVE_THREADS -DHAVE_DLOPEN -DHAVE_MMAP -DDB_185 -DCONFIG_FILE=\\\"/etc/hpsockd.conf\\\" -DSOCKD_PATH=\\\"/usr/sbin/hpsockd\\\" ${COMMON} LINUXCLFLAGS=-ldl -ldb LINUXDEBUG=-g LINUXOPT=-O hpsockd-0.17build2/src/util/0000755000000000000000000000000011024757214012633 5ustar hpsockd-0.17build2/src/util/btree.h0000644000000000000000000000324411024757214014110 0ustar #ifdef __cplusplus extern "C" { #endif /* (c) Copyright Hewlett-Packard Company 1993-2000. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef BTREE_H #define BTREE_H #if defined(__STDC__) && (__STDC__ != 0) #define BT_PROTOTYPES #define P_(x) x #else /* ! ANSI C */ #undef BT_PROTOTYPES #define P_(x) () #endif /* ! ANSI C */ /* flags for btsearch */ #define BT_INS 1 /* insert the key/data if not found */ #define BT_DEL 2 /* delete the key if found - used by bt delete */ #define BT_CLOSE 4 /* return closest (lower or equal) entry */ typedef enum { bt_first, bt_data, bt_last } btw_t; void* btsearch P_((void **root,void *key,void *data, int(*cmp)(void *k1,void *k2), int flags)); int btdelete P_((void **root,void *key,int(*cmp)(void *n1,void *n2))); int btwalk P_((void *root,int(*act)(void *key,void *data,btw_t which,void *info),void *info)); int btvalidate P_((void*pn, int(*cmp)(void *k1,void *k2))); void btdump P_((void *pn)); void btdestroy P_((void **root,int(*act)(void *key,void*data))); #endif /* BTREE_H */ #ifdef __cplusplus } #endif hpsockd-0.17build2/src/util/inet_ntoa.c0000644000000000000000000000432711024757214014765 0ustar #include #include #include #include #include #ifndef __lint static char *vers="@(#)$Header: /var/cvs/hpsockd/src/util/inet_ntoa.c,v 0.3 2000/12/08 20:49:44 lamont Exp $"; #endif /* (c) 1997-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /******************************************************************** * * inetNtoa() returns a character string for the address given to it. * It needs to toggle between two buffers, because some routines call * it twice before using the results... * ********************************************************************/ char *inetNtor(register long addr) { #define ADDR_SLEN 16 #define NUM_ADDR 2 static int which=0; static char str[NUM_ADDR][ADDR_SLEN]; register unsigned int haddr=ntohl(addr); register int v=which; const char *fmt; which=(which+1)%NUM_ADDR; if (addr&0xff) fmt="%d.%d.%d.%d"; else if (addr&0xffff) fmt="%d.%d.%d"; else if (addr&0xffffff) fmt="%d.%d"; else fmt="%d"; snprintf(str[v],ADDR_SLEN,fmt,(haddr>>24&0xff),(haddr>>16&0xff),(haddr>>8&0xff),(haddr&0xff)); return str[v]; #undef ADDR_SLEN #undef NUM_ADDR } char *inetNtoa(register long addr) { #define ADDR_SLEN 16 #define NUM_ADDR 2 static int which=0; static char str[NUM_ADDR][ADDR_SLEN]; register unsigned int haddr=ntohl(addr); register int v=which; which=(which+1)%NUM_ADDR; snprintf(str[v],ADDR_SLEN,"%d.%d.%d.%d",(haddr>>24&255),(haddr>>16&255),(haddr>>8&255),(haddr&255)); return str[v]; #undef ADDR_SLEN #undef NUM_ADDR } hpsockd-0.17build2/src/util/inetdsec.c0000644000000000000000000002326611024757214014606 0ustar #if !defined(__lint) static char *RCSid = "@(#)$Header: /var/cvs/hpsockd/src/util/inetdsec.c,v 0.5 2000/12/08 20:49:44 lamont Exp $"; #endif /* (c) Copyright 1988, 1997-2000, Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * header files */ #include #include #include #include #include #include #include #include #include #include typedef unsigned char byte; int DoInetdSec(char *,struct sockaddr_in,char *); static caddr_t attachline(void); static int internet_parse(caddr_t, byte *, caddr_t); static caddr_t nextline(int); static int readsecfile(caddr_t); #define TRUE 1 #define FALSE 0 #define SIZLINE 8192 static int readsec = 0; /* If 0, security file has not been read yet */ struct stat lastread; /* Last modification time when file last read */ struct secinfo { int allowed; char *list; } safe; FILE *securep; /* */ /* Secure returns: -1 for a remote host that failed the security check */ /* -2 stat call on security file failed */ /* 1 when there is no security file to check */ /* and 0 when the remote host passed the security check.*/ int DoInetdSec(char *service, struct sockaddr_in from, char *security_file) { struct stat lastmod; /* last modification time for security */ /* file right now. */ char *p, *addrpointer; long netaddr; int parsed; struct hostent *hostname; struct netent *netname; char buf[BUFSIZ]; char *lastp; if (stat(security_file, &lastmod) == -1) { if (errno == ENOENT) return 1; return -2; } if (!readsec || lastmod.st_mtime != lastread.st_mtime) { readsec = TRUE; securep = fopen(security_file, "r"); if (securep == NULL) return -2; if (!readsecfile(service)) { fclose(securep); (void)stat(security_file, &lastread); return 0; /* entry not found, allowed */ } fclose(securep); (void)stat(security_file, &lastread); } if (safe.list==NULL) return 0; /* entry not found, allowed */ /* find correct address to match remote host address */ addrpointer = inet_ntoa(from.sin_addr); #ifdef MSDOS hostname = gethostbyaddr((struct in_addr far *)&from.sin_addr, sizeof(struct in_addr), from.sin_family); #else hostname = gethostbyaddr((const char *)&from.sin_addr, sizeof(struct in_addr), from.sin_family); #endif /*MSDOS*/ netaddr = inet_netof(from.sin_addr); netname = getnetbyaddr(netaddr, AF_INET); (void)strcpy(buf, safe.list); lastp = &buf[strlen(buf)]; p = strtok(buf, " \t"); while (p != NULL) { /* if list member matches address, hostname or */ /* netname of the remote host, the remote host */ /* is allowed. */ if (!strcmp(p, addrpointer) || (hostname != NULL && !strcasecmp(p, hostname->h_name)) || (netname != NULL && !strcasecmp(p, netname->n_name))) { if (safe.allowed) return 0; else return -1; } /* Check for ranges and wild card characters */ parsed = internet_parse(p, (byte *)&from.sin_addr, service); if (parsed == 1) { if (safe.allowed) return 0; else return -1; } /* if the list member doesn't match anything, get */ /* next list member. */ /* strtok() is used in internet_parse() which causes */ /* problems because it overwrites the state we had so */ /* we need to specify the buffer again. */ p = &p[strlen(p)]; if (p == lastp) break; p = strtok(&p[1], " \t"); } /* end of while */ /* if the service was found but the host we are looking */ /* for is not in list, then if it was a list of allowed */ /* hosts the host is not allowed, and if it was a list */ /* of hosts not allowed, the host is allowed. */ if (safe.allowed) return -1; /* bad host */ return 0; } /* end of DoInetdSec */ /*** Internet_parse written Feb., 1986 by Cristina Mahon and Darren Smith **/ /*** routine to take a string, which represents an entry in the **/ /*** security file, and a pointer to an address in Internet format (i.e four **/ /*** bytes), and return an indication of whether the address matches the **/ /*** string, where the string can have wild cards and ranges **/ /*** returns a -1 in case of config error, a zero if it doesn't match **/ /*** and a 1 if it succeeds. **/ static internet_parse(char *string,byte *addr,char *service) { int i; /***** low, high, num, and addr are defined as unsigned chars to get **/ /***** the proper conversion, otherwise the byte vallues in chars ***/ /***** are converted to integers, which screws up the signs. **/ byte low, high; byte num; char *cp; char store[100]; /*** internet specifies 60 chars, + some ***/ char *list[4]; /*** If this is not an address: for example hostname or netname */ /*** return with no match. */ if ( strspn(string,"0123456789-*.") != strlen(string) ) return(0); /** save string before we destroy it! */ strncpy(store,string,sizeof(store)); cp = strtok(store,".\0"); for (i=0;i<4;i++) { list[i]=cp; cp = strtok(NULL,".\0"); if ( cp == NULL || *cp == '\0') cp = "*"; } for (i=0;i<4; i++) { /*** check for wild card. Only if it is exactly the **/ /*** string "*" will it match. ***/ if ( strcmp(list[i],"*") == 0 ) continue; /*** if it still contains a wild card, make it an error **/ if ( strchr(list[i],'*') != NULL ) { return(-1); } /*** check for a string with a range of numbers. **/ /*** no error checking for blanks, etc. **/ if ( (cp = strchr(list[i],'-')) != NULL ) { if( cp == list[i] ) /** no first number **/ { return(-1); } *cp = (char)NULL; cp++ ; if ( *cp == '\0' ) /** no second number **/ { return(-1); } /** get the two numbers **/ low = (byte)atoi(list[i]); high = (byte)atoi(cp); /*** this is a hack. We needed to pick out the **/ /*** four bytes in the in_addr structure and compare **/ /*** them one at a time. Since in_addr is not a **/ /*** array, we kludged it to look like an array **/ /*** of chars, which will be converted to integers **/ /*** by C when it does the actual comparison. SIGH **/ if( low <= addr[i] && addr[i] <= high ) continue; else if ( high < low ) { return(-1); } else return(0); } /*** end of if strchr(string,'-') **/ /**** check for the number exactly ***/ num = (byte)atoi(list[i]); if ( num == addr[i] ) continue; else return(0); } /***** end of for i = 0 to 3 ***/ /*** if made it this far, it succeeded ***/ return(1); } /*** end of internet_parse ***/ /* read the security file and fill the security structure with information */ static int readsecfile(char *service) { char *cp, *saveline; int lensafe; /* size of the list of hosts */ safe.allowed = FALSE; if (safe.list) free(safe.list); safe.list = NULL; while (TRUE) { if ((saveline = attachline()) == NULL) break; /* find service name */ if ((cp = strtok(saveline," \t\n")) == NULL) { free(saveline); continue; } if (!strcmp(service, cp)) break; else free(saveline); } /* while */ if (saveline == NULL) return 0; if ((cp = strtok(NULL," \t\n")) == NULL) { free(saveline); return 1; } if (!strcasecmp(cp, "allow")) safe.allowed = TRUE; else if (!strcasecmp(cp, "deny")) safe.allowed = FALSE; else { free(saveline); return 1; } while (*cp != '\0') cp++; cp++; while ((*cp == ' ')|| (*cp == '\t')) cp++; if ((*cp == '\n') || (*cp == '\0')) { free(saveline); return 1; } safe.list = strdup(cp); free(saveline); lensafe = strlen(safe.list); if (safe.list[lensafe - 1] == '\n') safe.list[lensafe - 1] = '\0'; return 1; } /* readsecfile */ static char * attachline(void) { char *p, *cp, *saveline; int len, newlen, i; /* get the next line ignoring blank lines */ if ((p = nextline(1)) == NULL) return (char *)NULL; while (*p == ' ' || *p == '\t') p++; /* skip any initial blanks */ saveline = strdup(p); cp = saveline; while (*cp != '\n') { if (*cp == '\\') { *cp = ' '; cp++; if (*cp == '\n') { len = cp - saveline; /* get the next line taking into account blank lines */ p = nextline(0); newlen = strlen(p); cp = saveline =(caddr_t)realloc(saveline,len+1+newlen+1); for (i=1; i<=len; i++) cp++; strcpy(cp,p); if (*p == '\n') return(saveline); } } cp++; } return(saveline); } /* end of attachline */ char *inetd_line=NULL; /* Get next line of the configuration file */ static char * nextline(int ignoreblklines) { char *cp; if (inetd_line==NULL) inetd_line=(char*)malloc(SIZLINE+1); while (TRUE) { if ((cp = fgets(inetd_line,SIZLINE, securep)) == NULL) return (char *)NULL; /* ignore blank lines unless we are attaching to previous */ /* line in which case it should not be ignored */ if ((*cp == '\n') && (ignoreblklines)) continue; /* skip blank lines */ if ((*cp == '#') && (ignoreblklines)) continue; /* skip comment lines */ if (strlen(cp) == strspn(cp, " \t\f\r\n")) continue; /* skip blank lines */ return(inetd_line); } } /* end of nextline */ hpsockd-0.17build2/src/util/btree.c0000644000000000000000000003172611024757214014111 0ustar #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include "btree.h" #ifndef __lint static char rev[] = "@(#) btree.c $Header: /var/cvs/hpsockd/src/util/btree.c,v 0.3 2000/12/08 20:49:44 lamont Exp $"; #endif /* (c) 1993-2000 Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ typedef struct node node_t; typedef struct elem elem_t; struct elem { void *key; union { node_t *child; /* pointer to next layer */ void *data; /* pointer to data */ } p; }; #ifndef E_PER_N #define E_PER_N 64 #endif typedef enum { n_leaf,n_interior } ntype_t; struct node { /*+00*/ node_t *left,*right; /*+08*/ node_t *parent; /*+0c*/ short nel; /*+0e*/ ntype_t n_type; /*+10*/ elem_t e[E_PER_N]; }; #define CMP int (*cmp)(void *k1,void *k2) static int find_ix P_((node_t *pn,void* key, CMP, int *rv)); static node_t *put_entry P_((node_t **root,node_t *pn,int ix, void *key, void *data, CMP)); static node_t *search P_((node_t **root,node_t *pn,void *key, void *data, CMP,int flags,void **user_ret)); #define SEQ_SWITCHOVER 2 #ifdef BT_PROTOTYPES static int find_ix(node_t *pn,void* key, CMP,int *rv) #else static int find_ix(node_t *pn,void* key, CMP,rv) node_t *pn; void* key; int (*cmp)(); int *rv; #endif { register int rval=-1; register int l,h,chk; /* find_ix searches the node whose address is passed as the pn parameter * to determine where to place the new 'key' * * cmp returns are modeled after strcmp; <0 if key1 < key2, etc. * * find_ix returns the index of the largest entry in the 'e' array * which is <= the supplied key, or -1 if the node is empty or if * the input key is less than the lowest entry in the node. * The idea is that the new key would be added after the index'd * entry whose index we return. */ if (pn->nel==0 || (rval=cmp(key,pn->e[0].key))<=0) { if (rv!=NULL) *rv=rval; return (rval==0) ? 0 : -1; } l=0; h=pn->nel; while (h-l > SEQ_SWITCHOVER) { chk=l+(h-l)/2; if ((rval=cmp(key,pn->e[chk].key))<0) h=chk; else if (rval==0) { if (rv!=NULL) *rv=rval; return chk; } else l=chk; } while (h>l+1 && (rval=cmp(key,pn->e[h-1].key))<=0) { h--; if (rval==0) { if (rv!=NULL) *rv=rval; return h; } } if (rv!=NULL) *rv=rval; return h-1; } static void fix_keys (node_t *pn,void *okey,CMP) { register int nix; register node_t *n=pn->parent; register void *nkey=pn->e[0].key; if (pn->nel==0) return; while (n != NULL) { nix=find_ix(n,okey,cmp,NULL); n->e[nix].key=nkey; if (nix != 0) n=NULL; else n=n->parent; } } #ifdef BT_PROTOTYPES static node_t *put_entry(node_t **root,node_t *pn,int ix, void *key, void *data, CMP) #else static node_t *put_entry(root,pn,ix, key, data,cmp) node_t **root; node_t *pn; int ix; void *key; void *data; int (*cmp)(); #endif { register node_t *newNode; /* insert the key/data pair into the node after the ix'th spot */ /* If the new entry will fit in the current node, add it */ if (pn->nelnel-ix-1>0) (void)memmove(pn->e+ix+2,pn->e+ix+1, (pn->nel-ix-1)*sizeof(elem_t)); pn->e[ix+1].key=key; pn->e[ix+1].p.data=data; pn->nel++; /* if this is a new lowest entry, follow the parent chain * up, fixing their keys. */ if (ix==-1) fix_keys(pn,pn->e[1].key,cmp); return NULL; } /* No room in this node, see if there's room in the siblings. */ if (pn->right != NULL && pn->right->nel < E_PER_N) { newNode=pn->right; (void)memmove(newNode->e+1,newNode->e,newNode->nel*sizeof(elem_t)); newNode->nel++; if (ix==E_PER_N-1) { newNode->e[0].key=key; newNode->e[0].p.data=data; if (newNode->n_type == n_interior) newNode->e[0].p.child->parent=newNode; fix_keys(newNode,newNode->e[1].key,cmp); return NULL; } else { newNode->e[0].key=pn->e[E_PER_N-1].key; newNode->e[0].p.data=pn->e[E_PER_N-1].p.data; pn->nel--; fix_keys(newNode,newNode->e[1].key,cmp); if (newNode->n_type == n_interior) newNode->e[0].p.child->parent=newNode; /* this time we'll have room. */ return put_entry(root,pn,ix,key,data,cmp); } } /* How about the left sibling */ if (pn->left != NULL && pn->left->nel < E_PER_N) { newNode=pn->left; newNode->e[newNode->nel].key=pn->e[0].key; newNode->e[newNode->nel].p.data=pn->e[0].p.data; if (newNode->n_type == n_interior) newNode->e[newNode->nel].p.child->parent=newNode; newNode->nel++; if (ix>0) (void)memmove(pn->e,pn->e+1,ix*sizeof(elem_t)); pn->e[ix].key=key; pn->e[ix].p.data=data; fix_keys(pn,newNode->e[newNode->nel-1].key,cmp); return NULL; } /* Split the node, which may involve more splitting... */ newNode=(node_t*)calloc(1,sizeof(node_t)); assert(newNode!=NULL); newNode->parent=pn->parent; newNode->left=pn; newNode->right=pn->right; if (pn->right != NULL) pn->right->left=newNode; pn->right=newNode; newNode->n_type=pn->n_type; newNode->nel=E_PER_N/2; pn->nel-=newNode->nel; (void)memcpy(newNode->e,pn->e+pn->nel,newNode->nel*sizeof(elem_t)); if (newNode->n_type == n_interior) { register int i; for (i=0;inel;i++) newNode->e[i].p.child->parent=newNode; } if (ix >= pn->nel) { ix-=pn->nel; if (newNode->nel-ix-1>0) (void)memmove(newNode->e+ix+2,newNode->e+ix+1, (newNode->nel-ix-1)*sizeof(elem_t)); newNode->e[ix+1].key=key; newNode->e[ix+1].p.data=data; newNode->nel++; if (newNode->n_type== n_interior) newNode->e[ix+1].p.child->parent=newNode; } else { if (pn->nel-ix-1>0) (void)memmove(pn->e+ix+2,pn->e+ix+1, (pn->nel-ix-1)*sizeof(elem_t)); pn->e[ix+1].key=key; pn->e[ix+1].p.data=data; pn->nel++; /* if this is a new lowest entry, follow the parent chain * up, fixing their keys. */ if (ix==-1) fix_keys(pn,pn->e[1].key,cmp); } /* if we just split the root, then make a new one. */ if (pn == *root) { *root=(node_t*)calloc(1,sizeof(node_t)); assert(*root!=NULL); (*root)->nel = 2; (*root)->n_type = n_interior; (*root)->e[0].key = pn->e[0].key; (*root)->e[0].p.child = pn; (*root)->e[1].key = newNode->e[0].key; (*root)->e[1].p.child = newNode; pn->parent=newNode->parent = *root; } /* return newNode, so the caller can insert that in the parent. */ return newNode; } #ifdef BT_PROTOTYPES static node_t *search(node_t **root,node_t *pn,void *key, void *data, CMP, int flags, void **user_ret) #else static node_t *search(root,pn, key, data, cmp, flags, user_ret) node_t **root; node_t *pn; void *key; void *data,**user_ret; int (*cmp)(); int flags; #endif { int rval; register int ix=find_ix(pn,key,cmp,&rval); if (pn->n_type==n_interior) { register nix=ix; register node_t *n; if (nix==-1) nix=0; if ((n=search(root,pn->e[nix].p.child,key,data,cmp, flags,user_ret)) != NULL) { nix=find_ix(pn,n->e[0].key,cmp,NULL); return put_entry(root,pn,nix,n->e[0].key, (void*)n,cmp); } return NULL; } else { register node_t *n=NULL,*nn=pn; register void *okey0=(pn->nel ? pn->e[0].key : key); if (user_ret != NULL) *user_ret=NULL; if (rval != 0) { /* couldn't find the beast */ if ((flags & BT_INS)) { n=put_entry(root,pn,ix,key,data,cmp); /* if we shifted one entry to the left sibling, then the e[0].key will have changed; otherwise, our entry is the one after ix. */ if (ix < 0 || pn->e[0].key == okey0) ix++; } else if (!(flags&BT_CLOSE)) return NULL; } if (flags&BT_INS) { /* if we're outside the bounds of the node, then we must have split */ if (ix >= pn->nel) { nn=pn->right; ix=ix-pn->nel; } /* was this a previously deleted key? */ if (nn->e[ix].p.data == NULL) nn->e[ix].p.data=data; } if (user_ret != NULL) *user_ret = nn->e[ix].p.data; if ((flags & BT_DEL)) { /* XXX - just mark it deleted for now */ nn->e[ix].p.data=NULL; } return n; } } #ifdef BT_PROTOTYPES void *btsearch(void **uroot,void *key,void *data, CMP, int flags) #else void *btsearch(uroot,key,data,cmp,flags) void **uroot; void *key,*data; int (*cmp)(); int flags; #endif { node_t **root=(node_t**)uroot; void *user_ret; if (*root == NULL) { register node_t *node; node=*root=(node_t*)calloc(1,sizeof(node_t)); assert(node!=NULL); node->n_type=n_leaf; node->nel=0; } (void)search(root,*root,key,data,cmp,flags,&user_ret); return user_ret; } #ifdef BT_PROTOTYPES int btdelete(void **uroot,void *key,CMP) #else int btdelete(uroot,key,cmp) void **uroot; void *key; int (*cmp)(); #endif { node_t **root=(node_t**)uroot; if (*root == NULL) return -1; search(root,*root,key,NULL,cmp,BT_DEL,NULL); return 0; } #ifdef BT_PROTOTYPES int btwalk(void *upn, int(*act)(void *key,void *data,btw_t which,void *info),void *info) #else int btwalk(upn,act,info) void *upn; int(*act)(); void *info; #endif { register node_t *pn=(node_t*)upn; register int i; register int ret; if (pn==NULL) return 1; while (pn->n_type == n_interior) { pn=pn->e[0].p.child; } ret=(*act)(NULL,NULL,bt_first,info); if (ret!=0) return ret; while (pn != NULL) { for (i=0;inel;i++) { if (pn->e[i].p.data != NULL) { ret=(*act)(pn->e[i].key,pn->e[i].p.data,bt_data,info); if (ret!=0) return ret; } } pn=pn->right; } return (*act)(NULL,NULL,bt_last,info); } #ifdef BT_PROTOTYPES static void destroy (void *upn,int(*act)(void *key,void*data)) #else static void destroy(upn,act) void *upn; int(*act)(); #endif { register node_t *pn=(node_t*)upn; register int i; if (pn->n_type == n_interior) { destroy(pn->e[0].p.child,act); } while (pn != NULL) { for (i=0;inel;i++) { if (pn->n_type==n_leaf) { if (act!=NULL) (*act)(pn->e[i].key,pn->e[i].p.data); } else { /* key is user data */ free(pn->e[i].p.child); } } pn=pn->right; } } #ifdef BT_PROTOTYPES void btdestroy (void **uroot,int(*act)(void *key,void*data)) #else void btdestroy(uroot,act) void **uroot; int(*act)(); #endif { register node_t **root=(node_t**)uroot; register int i; if (root==NULL||*root==NULL) return; if ((*root)->n_type == n_interior) { destroy((*root)->e[0].p.child,act); } for (i=0;i<(*root)->nel;i++) { if ((*root)->n_type==n_leaf) { if (act!=NULL) (*act)((*root)->e[i].key,(*root)->e[i].p.data); } else { /* key is user data */ free((*root)->e[i].p.child); } } free(*root); *root=NULL; } #define Fprintf (void)fprintf #ifdef BT_PROTOTYPES int btvalidate(void*upn,CMP) #else int btvalidate(upn,cmp) void *upn; int(*cmp)(); #endif { register node_t *pn=(node_t*)upn; register int i; register int errs=0; #define ERR(s,n) ( Fprintf(stderr,s,pn,n),errs++ ) if (pn->nel==0) { ERR("Empty node at %x\n",0); return errs; } if (pn->right !=NULL && (*cmp)(pn->e[pn->nel-1].key,pn->right->e[0].key)>=0) ERR("Key out of order/dup in %x[%d]\n",pn->nel-1); for (i=0;inel-1;i++) { if ((*cmp)(pn->e[i].key,pn->e[i+1].key)>=0) ERR("Key out of order/dup in %x[%d]\n",i); } if (pn->n_type == n_interior) { if (pn->left != NULL) { if (pn->e[0].p.child->left != pn->left->e[pn->left->nel-1].p.child) ERR("bad left pointer in %x[0]\n",0); } if (pn->right != NULL) { if (pn->e[pn->nel-1].p.child->right != pn->right->e[0].p.child) ERR("bad right pointer in %x[%d]\n",pn->nel-1); } for (i=0;inel;i++) { if (pn->e[i].key != pn->e[i].p.child->e[0].key) ERR("bad key in %x[%d]\n",i); if (i>0) { if (pn->e[i].p.child->left != pn->e[i-1].p.child) ERR("bad left pointer in %x[%d]\n",i); } if (inel-1) { if (pn->e[i].p.child->right != pn->e[i+1].p.child) ERR("bad right pointer in %x[%d]\n",i); if ((*cmp)(pn->e[i].key,pn->e[i+1].key)>=0) ERR("Key out of order/dup key in %x[%d]\n",i); } if (pn->e[i].p.child->parent != pn) ERR("bad parent pointer in %x[%d]\n",i); errs+=btvalidate(pn->e[i].p.child,cmp); } } return errs; } #ifdef BT_PROTOTYPES void btdump(void *upn) #else void btdump(upn) void *upn; #endif { static int lev=0; register int i; char indent[300]; register node_t *pn=(node_t*)upn; for (i=0;ileft,pn->right,pn->parent, pn->n_type == n_leaf ? "leaf" : "intr", pn->nel); for (i=0;inel;i++) { Fprintf(stderr,"%s %08x[%d] %08x %08x\n",indent, pn,i,pn->e[i].key, pn->e[i].p.data); if (pn->n_type == n_interior) btdump(pn->e[i].p.child); } lev--; } #ifdef __cplusplus } #endif hpsockd-0.17build2/src/util/inet_ntoa.h0000644000000000000000000000145011024757214014764 0ustar /* (c) Copyright Hewlett-Packard Company 1997-2000. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ char *inetNtor(register long addr); char *inetNtoa(register long addr); hpsockd-0.17build2/src/util/Makefile0000644000000000000000000000226511024757214014300 0ustar # (c) Copyright Hewlett-Packard Company 1997-2000 # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. include ../Makefile.flags SRC=btree.c inetdsec.c inet_ntoa.c OBJ=btree.o inetdsec.o inet_ntoa.o PROGRAMS=libutil.a default debug: ${MAKE} `uname -s`.debug opt: ${MAKE} `uname -s` include ../Makefile.os all: ${PROGRAMS} libutil.a: ${OBJ} ar rv $@ $? ranlib $@ clean: rm -f *.o clobber: clean rm -f ${PROGRAMS} print: @pr -n $$(echo RCS/*,v | sed 's/RCS.\([^,]*\),v/\1/g') # @pr -n ${CSRC} ${OSRC} ${DSRC} ${MSRC} ${LSRC} ${USRC} ${HSRC} hpsockd-0.17build2/src/Makefile0000644000000000000000000000475711024757214013333 0ustar # (c) Copyright Hewlett-Packard Company 1997-2000 # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. DIRS=util sockd #CC=purify -cache-dir=/users/lamont/.purify-cache -follow-child-processes=yes cc include Makefile.flags ROOT=root TEMPLATE=${ROOT}/opt/socks/newconfig/etc/opt/socks/sockd.conf.template default opt: ${MAKE} `uname -s` debug: ${MAKE} `uname -s`.debug include Makefile.os all clean clobber print: +for i in ${DIRS}; do (cd $$i && make $@); done install: all umask 0222 && mkdir -p ${ROOT}/opt/socks/bin umask 0222 && mkdir -p ${ROOT}/opt/socks/sbin cp sockd/sockd ${ROOT}/opt/socks/sbin cp sockd/sdc ${ROOT}/opt/socks/bin cp sockd/usage ${ROOT}/opt/socks/bin cp sockd/log2ascii ${ROOT}/opt/socks/bin umask 0222 && mkdir -p ${ROOT}/sbin/init.d if [ -d ../Fshp-ux ]; then \ cp ../Fshp-ux/sockd ${ROOT}/sbin/init.d/sockd; \ chmod 544 ${ROOT}/sbin/init.d/sockd; \ chown root:sys ${ROOT}/sbin/init.d/sockd; \ fi umask 0222 && mkdir -p ${ROOT}/sbin/rc2.d ${ROOT}/sbin/rc1.d ln -sf /sbin/init.d/sockd ${ROOT}/sbin/rc2.d/S900sockd ln -sf /sbin/init.d/sockd ${ROOT}/sbin/rc1.d/K100sockd umask 0222 && mkdir -p ${ROOT}/opt/socks/doc cp ../doc/config.html ${ROOT}/opt/socks/doc cp ../doc/sdc.html ${ROOT}/opt/socks/doc cp ../doc/signals.html ${ROOT}/opt/socks/doc cp ../doc/rfc*.txt ${ROOT}/opt/socks/doc cp sockd/ChangeLog ${ROOT}/opt/socks/doc/Changelog chmod 444 ${ROOT}/opt/socks/doc/Changelog chown root:sys ${ROOT}/opt/socks/doc/Changelog umask 0222 && mkdir -p ${ROOT}/var/opt/socks umask 0222 && mkdir -p ${ROOT}/opt/socks/newconfig/etc/opt/socks cp sockd/sockd.conf.template ${TEMPLATE} chmod 444 ${TEMPLATE} chown root:sys ${TEMPLATE} dist: mkdir -p ../dist/src ../dist/doc find . \( -name RCS -o -name test \) -prune -o -print | cpio -pdlmauxv ../dist/src cd ../doc && find . -name RCS -prune -o -print | cpio -pdlmauxv ../dist/doc hpsockd-0.17build2/maketape0000755000000000000000000000600511024757214012605 0ustar #!/bin/ksh PATH=${PATH}:/usr/sbin # usage maketape fset > PSF dep() { case $1 in SOCKS-SERV) ;; *) print -u2 Unknown fileset ${fs}; exit 1;; esac return 0 } desc() { case $1 in SOCKS-SERV) fd="Socks Server";; *) print -u2 Unknown fileset ${fs}; exit 1;; esac print ${fd} return 0 } tape_fpkg() { typeset fsets=$1 typeset vers=$2 typeset osrel=$3 print "media_format A.B8.05" for fs in $(cd $fsets; /bin/ls -d [A-Z]*); do mkdir -p ${fsets}/${fs}/system/${fs} for f in customize decustomize; do if [[ -f Fshp-ux/${fs}/$f ]]; then rm -f ${fsets}/${fs}/system/${fs}/${f} ln -f Fshp-ux/${fs}/${f} ${fsets}/${fs}/system/${fs} fi done pn=SOCKS pd="Socks" dep="" cat <<-EOF ######## # Begin Fileset: ${fs} # pn ${pn} pd "${pd}" fn ${fs} fd "$(desc ${fs})" fv $vers ff CD $(dep ${fs}) media_order 6 pr $(pwd)/${fsets}/${fs}/=/ # fdperm bin bin 555 F * # End of Fileset: ${fs} EOF done print "########" return 0 } tape_swpackage() { typeset fsets=$1 typeset vers=$2 typeset osrel=$3 cat <${psf} swpackage -xlogfile=${log} -xtarget_type=tape -s ${psf} \ -d Bin/tape.${arch} grep -e '^[EW]' ${log} && print "see ${log} for details" || rm ${log} ;; 800*) tape_fpkg $fsets $vers $osrel > ${psf} fpkg -m tape -a Bin/tape.${arch} -S ${arch%.*} -L ${log} ${a2} ${psf} grep -e '^[EW]' ${log} && print "see ${log} for details" || rm ${log} ;; esac hpsockd-0.17build2/debian/0000755000000000000000000000000012235035506012307 5ustar hpsockd-0.17build2/debian/dirs0000644000000000000000000000021511024757214013173 0ustar /etc/init.d /usr/sbin /usr/lib/hpsockd /usr/share/doc/hpsockd /usr/share/doc/hpsockd/examples /usr/share/doc/hpsockd/html /var/cache/hpsockd hpsockd-0.17build2/debian/copyright0000644000000000000000000000136311024757214014247 0ustar This is the Debian GNU/Linux prepackaged version of hpsockd, a SOCKS daemon, copyright Hewlett-Packard Company, as indicated in the source code. Copyright (c) 1997-2001,2007 by Hewlett-Packard Company. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 dated June, 1991. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. A copy of the GNU General Public License is available on Debian GNU/Linux systems as /usr/share/common-licenses/GPL. hpsockd-0.17build2/debian/postrm0000644000000000000000000000167311024757214013567 0ustar #! /bin/sh # postrm script for #PACKAGE# # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `purge' # * `upgrade' # * `failed-upgrade' # * `abort-install' # * `abort-install' # * `abort-upgrade' # * `disappear' overwrit>r> # for details, see /usr/share/doc/packaging-manual/ case "$1" in remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) ;; purge) update-rc.d hpsockd remove >/dev/null rm -f /var/cache/hpsockd/negot_file ;; *) echo "postrm called with unknown argument \`$1'" >&2 exit 0 esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# hpsockd-0.17build2/debian/doc-base0000644000000000000000000000031511024757214013710 0ustar Document: hpsockd Title: HP SOCKS documentation Author: LaMont Jones Section: Apps/Net Format: HTML Index: /usr/share/doc/hpsockd/html/index.html Files: /usr/share/doc/hpsockd/html/*.html hpsockd-0.17build2/debian/init.d0000755000000000000000000000243411024757214013427 0ustar #! /bin/sh ### BEGIN INIT INFO # Provides: hpsockd # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: start and stop the HP Socks daemon # Description: hpsockd is a Socks Daemon ### END INIT INFO PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/hpsockd NAME=hpsockd DESC="HP SOCKS daemon" test -f $DAEMON || exit 0 set -e case "$1" in start) if [ -f /etc/hpsockd.conf ]; then echo -n "Starting $DESC: " start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ --exec $DAEMON echo "$NAME." else echo "Not starting $DESC: no config file." fi ;; stop) echo -n "Stopping $DESC: " start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ --exec $DAEMON echo "$NAME." ;; reload|force-reload) echo "Reloading $DESC configuration files." /usr/sbin/sdc reload ;; restart) echo -n "Restarting $DESC: " start-stop-daemon --stop --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON sleep 1 start-stop-daemon --start --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON echo "$NAME." ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 exit 1 ;; esac exit 0 hpsockd-0.17build2/debian/changelog0000644000000000000000000001325612235035506014170 0ustar hpsockd (0.17build2) trusty; urgency=low * No change rebuild against db 5.3. -- Dmitrijs Ledkovs Fri, 01 Nov 2013 23:37:42 +0000 hpsockd (0.17build1) precise; urgency=low * Rebuild for libdb5.1. -- Colin Watson Fri, 11 Nov 2011 23:18:15 +0000 hpsockd (0.17) unstable; urgency=low * Drop documenation to make the pedants happy. Closes: #480372 -- LaMont Jones Sat, 14 Jun 2008 09:05:19 -0600 hpsockd (0.16) unstable; urgency=low [Petter Reinholdtsen] * init.d: add LSB init stuff. Closes: #462716 -- LaMont Jones Fri, 28 Mar 2008 07:45:51 -0600 hpsockd (0.15) unstable; urgency=low * Use libdb 4.6. Closes: #421941 * Support GNU/kFreeBSD. Closes: #414971 * Remove negot_file on purge. Closes: #328321 * Document git repository location * Debhelper 5 * Copyright GPLv2 -- LaMont Jones Tue, 11 Sep 2007 12:02:56 -0600 hpsockd (0.14) unstable; urgency=low * Better handle short udp packets -- LaMont Jones Wed, 10 Nov 2004 14:33:25 -0700 hpsockd (0.13) unstable; urgency=low * Use db4.2 instead of db4.1. Closes: #263234 * Fix gcc-3.4 errors. Closes: #263236 -- LaMont Jones Sun, 12 Sep 2004 12:01:32 -0600 hpsockd (0.12) unstable; urgency=low * Fix description. Closes: #135448, #209646 * Handle missing config file in init.d better. Closes: #131618 -- LaMont Jones Sat, 13 Sep 2003 20:11:08 -0600 hpsockd (0.11) unstable; urgency=low * Remove RFC's from the package. Closes: #199805 -- LaMont Jones Fri, 29 Aug 2003 09:58:12 -0600 hpsockd (0.10) unstable; urgency=low * Add -v option to print version. -- LaMont Jones Thu, 27 Feb 2003 10:23:44 -0700 hpsockd (0.9) unstable; urgency=low * Fix bad sign assumption. Closes: #177386 -- LaMont Jones Sun, 19 Jan 2003 07:04:22 -0700 hpsockd (0.8) unstable; urgency=high * Cleanup ping/traceroute command handling. -- LaMont Jones Mon, 16 Dec 2002 22:19:24 -0700 hpsockd (0.7) unstable; urgency=low * Add more footprinting. * 2.4 select appears to return true for read on non-connected sockets. Avoid that. -- LaMont Jones Fri, 26 Jul 2002 21:12:14 -0600 hpsockd (0.6) unstable; urgency=low * use anonymous mmap regions for client buffer memory, so that we can give it back to the kernel when the client goes away. -- LaMont Jones Tue, 26 Mar 2002 20:44:32 -0700 hpsockd (0.5.1) unstable; urgency=low * Add footprint call on ENOBUFS in accept. -- LaMont Jones Mon, 28 Jan 2002 11:14:17 -0700 hpsockd (0.5) unstable; urgency=low * Fix corner case with dnsHandler dying causing corruption in the connection data structures. Closes: #127721. * Don't keep accepting data when the other side is blocked. * Allow limits on number of clients-per-minute. * sdc dumpconfig caused freeing-free-pointer problems. -- LaMont Jones Fri, 28 Dec 2001 23:11:34 -0700 hpsockd (0.4) unstable; urgency=low * Add undocumented links for now. -- LaMont Jones Sat, 22 Dec 2001 19:50:51 -0700 hpsockd (0.3.9) unstable; urgency=low * Try accepting up to 10 clients each pass through the select loop. -- LaMont Jones Mon, 17 Dec 2001 10:29:04 -0700 hpsockd (0.3.8) unstable; urgency=low * We were leaking the dns helper socket at spawnChild() time. Don't do that. * Don't prevent core files when debug!=0; default debug to DBG_SANITY. -- LaMont Jones Thu, 6 Dec 2001 13:04:30 -0600 hpsockd (0.3.7) unstable; urgency=low * Handle fdInfo overflow in udpAssoc. -- LaMont Jones Wed, 14 Nov 2001 15:09:28 -0600 hpsockd (0.3.6) unstable; urgency=low * More highFd fixes, more footprinting. * reduce memory footprint more agressively. -- LaMont Jones Wed, 14 Nov 2001 12:08:15 -0600 hpsockd (0.3.5) unstable; urgency=low * Bump highFd in listenRecv, to handle closing things properly in spawnChild. -- LaMont Jones Wed, 7 Nov 2001 23:43:33 -0600 hpsockd (0.3.4) unstable; urgency=low * More fingerprinting, sanity checks on data structures. -- LaMont Jones Thu, 1 Nov 2001 10:11:22 -0600 hpsockd (0.3.3) unstable; urgency=low * Fix footprinting code. sigh. -- LaMont Jones Thu, 23 Aug 2001 11:26:15 -0600 hpsockd (0.3.2) unstable; urgency=low * Add footprinting code to track down problems. -- LaMont Jones Tue, 29 May 2001 11:40:15 -0600 hpsockd (0.3.1) unstable; urgency=low * Start allowing alternate storage techniques for userpass. * point at syslog on config file parse errors. -- LaMont Jones Mon, 26 Mar 2001 10:26:20 -0700 hpsockd (0.3) unstable; urgency=low * Fix the path for hpsockd in sdc. Fixes segv on restart and start. * Port and host comparisons were trying to compare network byte order values. -- LaMont Jones Thu, 1 Mar 2001 22:03:46 -0700 hpsockd (0.2) unstable; urgency=low * Add byacc to build-depends, remove version of libdb2-dev. * Times and ID's in logfiles should be in network byte order. -- LaMont Jones Thu, 1 Mar 2001 12:26:27 -0700 hpsockd (0.1-2) unstable; urgency=low * Lintian cleanup. * Network byte order problems, null pointer issues... -- LaMont Jones Thu, 22 Feb 2001 20:10:13 -0700 hpsockd (0.1-1) unstable; urgency=low * New package -- LaMont Jones Thu, 15 Feb 2001 20:22:40 -0700 hpsockd-0.17build2/debian/postinst0000644000000000000000000000264311024757214014124 0ustar #! /bin/sh # postinst script for #PACKAGE# # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `configure' # * `abort-upgrade' # * `abort-remove' `in-favour' # # * `abort-deconfigure' `in-favour' # `removing' # # for details, see /usr/share/doc/packaging-manual/ # # quoting from the policy: # Any necessary prompting should almost always be confined to the # post-installation script, and should be protected with a conditional # so that unnecessary prompting doesn't happen if a package's # installation fails and the `postinst' is called with `abort-upgrade', # `abort-remove' or `abort-deconfigure'. case "$1" in configure) update-rc.d hpsockd defaults > /dev/null cd /var/cache/hpsockd if [ ! -f negot_file ]; then dd if=/dev/zero of=negot_file bs=4k count=1 >/dev/null 2>&1 chown nobody . negot_file fi ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 0 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 hpsockd-0.17build2/debian/control0000644000000000000000000000117212235035507013714 0ustar Source: hpsockd Section: net Priority: extra Maintainer: Ubuntu Developers XSBC-Original-Maintainer: LaMont Jones Build-Depends: libdb-dev (>=4.6.19), debhelper (>=5), flex, byacc Standards-Version: 3.7.3 XS-Vcs-Browser: http://git.debian.org/?p=users/lamont/hpsockd.git XS-Vcs-Git: git://git.debian.org/~lamont/hpsockd.git Package: hpsockd Architecture: any Depends: ${shlibs:Depends} Description: HP SOCKS server Hpsockd is yet-another SOCKS server, with both version 5 (RFC1928 and others) as well as version 4 support, originally written at Hewlett-Packard Company. hpsockd-0.17build2/debian/rules0000755000000000000000000000363711024757214013402 0ustar #!/usr/bin/make -f # Based on sample debian/rules, GNU copyright 1997-1999 by Joey Hess. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 package=hpsockd docdir=debian/$(package)/usr/share/doc/$(package) sbindir=debian/$(package)/usr/sbin bindir=debian/$(package)/usr/bin lbindir=debian/$(package)/usr/lib/hpsockd configure: configure-stamp configure-stamp: dh_testdir # Add here commands to configure the package. #CONFIGURE# touch configure-stamp build: configure-stamp build-stamp build-stamp: dh_testdir # Add here commands to compile the package. cd src && $(MAKE) touch build-stamp clean: dh_testdir dh_testroot rm -f build-stamp configure-stamp # Add here commands to clean up after the build process. cd src && $(MAKE) clobber dh_clean install: build dh_testdir dh_testroot dh_clean -k dh_installdirs # Add here commands to install the package into debian/#PACKAGE#. install src/sockd/sockd $(sbindir)/hpsockd install src/sockd/sdc $(sbindir) install src/sockd/usage src/sockd/log2ascii $(lbindir) install -m 444 doc/*.html $(docdir)/html install -m 444 src/sockd/ChangeLog $(docdir)/changelog install -m 444 src/sockd/sockd.conf.debian $(docdir)/examples/hpsockd.conf install debian/init.d debian/$(package)/etc/init.d/hpsockd # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. # Build architecture-dependent files here. binary-arch: build install dh_testdir dh_testroot # dh_installdebconf dh_installdocs dh_installexamples dh_installmenu # dh_installemacsen # dh_installpam # dh_installinit dh_installcron dh_installmanpages dh_installinfo dh_installchangelogs #CHANGELOGS# dh_link dh_strip dh_compress dh_fixperms # dh_makeshlibs dh_installdeb # dh_perl dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install configure hpsockd-0.17build2/debian/docs0000644000000000000000000000000011024757214013152 0ustar hpsockd-0.17build2/debian/compat0000644000000000000000000000000211024757214013507 0ustar 5