⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linetd.c

📁 linetd是一个压缩TCP高级服务器。所有的设置值都受控于命令行。与tcp服务器或sinetd类似。
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <stdarg.h>#include <ctype.h>#include <errno.h>#include <limits.h>#include <pwd.h>#include <grp.h>#include <sched.h>#include <signal.h>#include <netdb.h>#include <sysexits.h>#include <fcntl.h>#include <sys/wait.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/resource.h>#include <arpa/inet.h>#include <netinet/in.h>#include <netinet/ip.h>#ifdef USE_IDSA#include <idsa_internal.h>/* The below requires idsa-0.93.8 or newer *//* linetd uses both the IDSA_SSM and IDSA_ES schemes */#include <idsa_schemes.h>/* names defined for the linetd scheme */#define LINET_EU   "error-usage"#define LINET_ES   "error-system"#define LINET_EI   "error-init"#define LINET_EF   "error-fork"#define LINET_CC   "client-connect"#define LINET_DR   "daemon-ready"#define LINET_DE   "daemon-exit"#define LINET_JD   "job-done"#define LINET_JE   "job-error"#define LINET_JS   "job-signal"#endif#define LINETD   "linetd"#define LINET_SCHEME  LINETD#define LINET_SERVICE LINETD#define LINET_TCP   "tcp"#define LINET_USAGE    1#define LINET_SYSTEM   2#define LINET_BUFFER 512#define LINET_SLEEP    5#define LINET_MAXRES  16#define LINET_READBUF 32#define LOADAVG "/proc/loadavg"#ifndef VERSION#define VERSION "unknown"#endifvolatile int run = 1;volatile int zombies = 0;int child_count = 0;int load_fd = (-1);int resource_table[LINET_MAXRES][2];int resource_count = 0;#ifdef USE_IDSAIDSA_CONNECTION *ic = NULL;#endifstatic void handle_child(int s){  zombies = 1;}static void handle_stop(int s){  run = 0;}static double get_load(){  char buffer[LINET_READBUF];  if(lseek(load_fd,0,SEEK_SET)){    return 0.0;  }  if(read(load_fd,buffer,LINET_READBUF) <= 0){    return 0.0;  }  buffer[LINET_READBUF-1]='\0';  return atof(buffer);}static void fatal_failure(int type, int error, char *message, ...){  va_list args;  char buffer[LINET_BUFFER];  int exitcode;  exitcode = EX_UNAVAILABLE;#ifdef USE_IDSA  if (ic == NULL) {    ic = idsa_open(LINET_SERVICE, NULL, 0);  }#endif  va_start(args, message);  vsnprintf(buffer, LINET_BUFFER - 1, message, args);  buffer[LINET_BUFFER - 1] = '\0';  va_end(args);  switch (type) {  case LINET_USAGE:#ifdef USE_IDSA    idsa_set(ic, LINET_EU, LINET_SCHEME, 0, IDSA_R_TOTAL, IDSA_R_NONE, IDSA_R_UNKNOWN,         IDSA_SSM,  IDSA_T_STRING, IDSA_SSM_SFAIL,         IDSA_ES,   IDSA_T_STRING, IDSA_ES_USAGE,         "comment", IDSA_T_STRING, buffer,         NULL);#endif    fprintf(stderr, "%s: %s\n", LINETD, buffer);    exitcode = EX_USAGE;    break;  case LINET_SYSTEM:#ifdef USE_IDSA    idsa_set(ic, LINET_ES, LINET_SCHEME, 0, IDSA_R_TOTAL, IDSA_R_NONE, IDSA_R_UNKNOWN,         IDSA_SSM,  IDSA_T_STRING, IDSA_SSM_SFAIL,         IDSA_ES,   IDSA_T_STRING, IDSA_ES_SYSTEM,         "comment", IDSA_T_STRING, buffer,        "code",    IDSA_T_ERRNO, &error,         NULL);#endif    fprintf(stderr, "%s: %s: %s\n", LINETD, buffer, strerror(error));    exitcode = EX_OSERR;    break;  }#ifdef USE_IDSA  if (ic) {    idsa_close(ic);    ic = NULL;  }#endif  exit(exitcode);}static void fork_parent(char *name){  int p[2];  pid_t pid;  char buffer[LINET_BUFFER];  /* int kfd, maxfd; */  int rr, status, result;  if (pipe(p)) {    fatal_failure(LINET_SYSTEM, errno, "unable to create pipe");  }  fflush(stderr);  pid = fork();  switch (pid) {  case -1:    fatal_failure(LINET_SYSTEM, errno, "unable to fork");    break;  case 0:			/* in child - make pipe stderr and detach from terminal */    close(p[0]);    if (dup2(p[1], STDERR_FILENO) != STDERR_FILENO) {      fatal_failure(LINET_SYSTEM, errno, "unable to duplicate stdandard error file descriptor");    }    close(p[1]);    close(STDOUT_FILENO);    close(STDIN_FILENO);    /* ugly, double edged sword */    /*    maxfd = getdtablesize();    for (kfd = STDERR_FILENO + 1; kfd < maxfd; kfd++) {      close(kfd);    }     */    setsid();    break;  default:			/* in parent - read from pipe, exit when pipe closes */    close(p[1]);    do {      rr = read(p[0], buffer, LINET_BUFFER);      switch (rr) {      case -1:	switch (errno) {	case EAGAIN:	case EINTR:	  rr = 1;	  break;	default:	  fprintf(stderr, "%s: unable to read child messages: %s\n", name, strerror(errno));	  fflush(stderr);	  break;	}	break;      case 0:	/* eof */	break;      default:	write(STDERR_FILENO, buffer, rr);	/* don't care if write fails, can't do anything about it */	break;      }    } while (rr > 0);    sched_yield();    result = 0;    if (waitpid(pid, &status, WNOHANG) > 0) {	/* got a child */      result = EX_SOFTWARE;      if (WIFEXITED(status)) {	result = WEXITSTATUS(status);	snprintf(buffer, LINET_BUFFER, "exited with code %d", result);      } else if (WIFSIGNALED(status)) {	snprintf(buffer, LINET_BUFFER, "killed by signal %d\n", WTERMSIG(status));      } else {	snprintf(buffer, LINET_BUFFER, "unknown exit condition");      }      buffer[LINET_BUFFER - 1] = '\0';#ifdef USE_IDSA      idsa_set(ic, LINET_EI, LINET_SCHEME, 0, IDSA_R_PARTIAL, IDSA_R_UNKNOWN, IDSA_R_PARTIAL,           IDSA_SSM,  IDSA_T_STRING, IDSA_SSM_SFAIL,           IDSA_ES,   IDSA_T_STRING, IDSA_ES_OTHER,           "comment", IDSA_T_STRING, buffer,           NULL);#endif      fprintf(stderr, "%s: %s\n", LINETD, buffer);      fflush(stderr);    }    /* else child probably ok */    exit(result);    break;  }}static void drop_root(char *name, char *user, char *group, char *root){  uid_t uid = 0;  gid_t gid = 0;  struct passwd *pw;  struct group *gr;  if (user) {    uid = atoi(user);    if (uid == 0) {      pw = getpwnam(user);      if (pw == NULL) {	fatal_failure(LINET_SYSTEM, errno, "unable to find user %s", user);      } else {	uid = pw->pw_uid;	gid = pw->pw_gid;      }    }  }  if (group) {    gid = atoi(group);    if (gid == 0) {      gr = getgrnam(group);      if (gr == NULL) {	fatal_failure(LINET_SYSTEM, errno, "unable to find group %s", group);      } else {	gid = gr->gr_gid;      }    }  }  if (root != NULL) {		/* do chroot */    if (chroot(root)) {      fatal_failure(LINET_SYSTEM, errno, "unable to change root directory to %s", root);    }  }  chdir("/");  if(getuid()==0){    if(setgroups(0,NULL)){      fatal_failure(LINET_SYSTEM, errno, "unable to delete supplementary groups");    }  }  if (group || user) {    if (setgid(gid)) {      fatal_failure(LINET_SYSTEM, errno, "unable to change gid to %lu", (unsigned long) gid);    }  }  if (user) {			/* now change id */    if (setuid(uid)) {      fatal_failure(LINET_SYSTEM, errno, "unable to change uid to %lu", (unsigned long) uid);    }  }}static void usage(char *name){  printf(    "Usage: %s [-cdfhv] "#ifdef USE_IDSA    "[-k[a|c|i] risk] [-x[e|o|u]] "#endif    "[-a[k|r]] [-b address] [-u user] [-g group] [-i instances] [-l load] [-m timeout] [-n nice] [-o[c|d|r|t]] -p port [-q backlog] [-r directory] [-s[c|d|f|l|m|n|s|t|u|v] limit] [-t ttl] path [options ...]\n\n" , name);  printf("Options:\n"    "-a[k|r]       disable k)eepalive or address r)euse socket option\n"    "-b address    bind a particular address instead of all available ones\n"    "-d            disable sanity checks\n"    "-f            do not fork into the background\n"    "-g gid        run with group id\n"    "-h            this help\n"    "-i integer    maximum number of child instances created\n"#ifdef USE_IDSA    "-k? risk      risk values: a)vailability, c)onfidentiality, i)ntegrity\n"#endif    "-l double     load average above which service is disabled\n"    "-m timeout    schedule an alarm signal for each child\n"    "-n level      run at reduced priority\n"    "-o?           type of service [tos]: optimal d)elay, r)eliability or t)hroughput\n"    "-p port       port to listen on [required]\n"    "-q backlog    number of connections queued in listen\n"    "-r directory  chroot into directory\n"    "-s? value     resource limit set for child\n"    "-t integer    time to live [ttl] counter\n"    "-u uid        run with user id\n"    "-v            print version and exit\n"#ifdef USE_IDSA    "-x?           enable flag: honour e)nvironment variable IDSA_SOCKET, fail o)pen, allow u)ploading of rules\n"#endif    "\n"  );  printf("Examples:\n");  printf("\n%s -u nobody -or -i 5 -m 5 -p finger /usr/sbin/in.fingerd in.fingerd -l\n", name);  printf(    "  Run fingerd as nobody.\n"    "  Maximize reliability of the TCP/IP connection.\n"    "  Start at most 5 fingerd instances and send a SIG_ALARM after 5 seconds.\n"  );  printf("\n%s -u nobody -p 2300 -t 1 /usr/bin/tail tail /var/log/apache/access_log\n", name);  printf(    "  Display the last lines of a log file to those connecting on port 2300.\n"    "  Set TTL to 1 which makes it inaccessible to users outside the subnet.\n"  );#ifdef USE_IDSA  printf("\nIDSA_SOCKET=/tmp/idsa %s -i1 -unobody -n5 -l2.0 -m10 -su0 -sm4096 -xexo -kc0.7/0.3 -ki0.2/0.3 -pnetstat /bin/netstat netstat -tn\n", name);  printf(    "  Run at most one instance of netstat as nobody at nice level 5.\n"    "  Stop this service if the system load is greater than 2.0.\n"    "  Schedule a SIG_ALARM if netstat hasn't completed after 10 seconds.\n"    "  Do not allow netstat to spawn a subprocess or occupy more than 4096k of RAM.\n"    "  Connect to idsad listening on socket /tmp/idsa but continue if no idsad is available.\n"    "  Reporting each new connection as having a high (0.7) risk to confidentiality but a low (0.2) risk to integrity.\n"  );#endif}static int setup_listener(char *name, char *port, char *interface, int queue, int ttl, int tos, int reuse, int keepalive){  int fd;  struct sockaddr_in addr;  int addrlen;  int prt;  struct hostent *hst;  struct servent *srv;  addr.sin_family = AF_INET;  if (port == NULL) {    fatal_failure(LINET_USAGE, 0, "require a port to bind");  }  prt = atoi(port);  if (prt == 0) {    srv = getservbyname(port, LINET_TCP);    if (srv == NULL) {      fatal_failure(LINET_USAGE, 0, "could not convert %s to a nonzero number", port);    }    addr.sin_port = srv->s_port;  } else {    addr.sin_port = htons(prt);  }  if (interface) {    if (inet_aton(interface, &(addr.sin_addr)) == 0) {      hst = gethostbyname(interface);      if (hst == NULL) {	fatal_failure(LINET_USAGE, 0, "could not convert %s to an address", interface);      }      if (hst->h_addrtype != AF_INET) {	fatal_failure(LINET_USAGE, 0, "%s does not resolve to an ip4 address", interface);      }      addr.sin_addr = *(struct in_addr *) hst->h_addr;    }  } else {    addr.sin_addr.s_addr = htonl(INADDR_ANY);  }  fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  if (fd < 0) {    fatal_failure(LINET_SYSTEM, errno, "could not create an internet socket");  }  if(reuse){    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse, sizeof(int));  }  if(keepalive){    setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(int));  }  addrlen = sizeof(addr);  if (bind(fd, (struct sockaddr *) &addr, addrlen) == (-1)) {    fatal_failure(LINET_SYSTEM, errno, "could not bind an internet socket");  }  if (listen(fd, queue) == (-1)) {    fatal_failure(LINET_SYSTEM, errno, "could not listen on socket");  }  if(ttl) {    if (setsockopt(fd, SOL_IP, IP_TTL, (void *)&ttl, sizeof(int))) {      fatal_failure(LINET_SYSTEM, errno, "could not set time to live to %d hops", ttl);    }  }  if(tos) {    if (setsockopt(fd, SOL_IP, IP_TOS, (void *)&tos, sizeof(int))) {      fatal_failure(LINET_SYSTEM, errno, "could not set type of service to 0x%02x", tos);    }  }  return fd;}static int run_command(int lfd, char *cmd, char **vector, int fd, int timeout){  struct sigaction sag;  sigset_t sst;  struct rlimit r;  int i;#ifdef USE_IDSA  int error;#endif  switch (fork()) {  case -1:#ifdef USE_IDSA    error = errno;    idsa_set(ic, LINET_EF, LINET_SCHEME, 0, IDSA_R_PARTIAL, IDSA_R_NONE, IDSA_R_PARTIAL,         IDSA_SSM,  IDSA_T_STRING, IDSA_SSM_WFAIL,         IDSA_ES,   IDSA_T_STRING, IDSA_ES_SYSTEM,         "comment", IDSA_T_STRING, "unable to create child process",         "code",    IDSA_T_ERRNO, &error,         NULL);#endif    close(fd);    return -1;    break;  case 0:    close(lfd);    if(load_fd>=0){      close(load_fd);    }#ifdef USE_IDSA    idsa_close(ic);#endif    sag.sa_handler = SIG_DFL;    sigemptyset(&(sag.sa_mask));    sag.sa_flags = SA_RESTART;    /* is this the correct way of resetting signal handlers ? */    sigaction(SIGCHLD, &sag, NULL);    sigaction(SIGTERM, &sag, NULL);    /* I haven't touched these, but it would seem important */    sigaction(SIGALRM, &sag, NULL);    sigaction(SIGPIPE, &sag, NULL);    sigemptyset(&sst);    sigaddset(&sst, SIGCHLD);    sigaddset(&sst, SIGTERM);    sigprocmask(SIG_UNBLOCK, &sst, NULL);	/* enable child signal */    if ((fd != STDIN_FILENO) && (dup2(fd, STDIN_FILENO) != STDIN_FILENO)) {      exit(EX_OSERR);    }    if ((fd != STDOUT_FILENO)	&& (dup2(fd, STDOUT_FILENO) != STDOUT_FILENO)) {      exit(EX_OSERR);    }    if ((fd != STDERR_FILENO)	&& (dup2(fd, STDERR_FILENO) != STDERR_FILENO)) {      exit(EX_OSERR);    }    if (fd > STDERR_FILENO) {      close(fd);    }    for(i = 0; i < resource_count; i++){      r.rlim_cur = resource_table[i][1];      r.rlim_max = resource_table[i][1];      if (setrlimit(resource_table[i][0], &r)) {        exit(EX_OSERR);      }    }    if (timeout) {      alarm(timeout);    }    execv(cmd, vector);#ifndef PARANOID    fprintf(stderr, "unable to run %s: %s\n", vector[0], strerror(errno));#endif    exit(EX_UNAVAILABLE);    break;  default:    child_count++;    close(fd);    return 0;    break;  }  return 0;}#ifdef USE_IDSAstatic int accept_connection(int lfd, unsigned ar, unsigned cr, unsigned ir)#elsestatic int accept_connection(int lfd)#endif{  struct sockaddr_in addr;  int addrlen;  int nfd;  sigset_t sst;#ifdef USE_IDSA  int len;  int cp[2], sp[2];  unsigned long ca, sa;  int ttl;  int complete;  char *reason;#endif  sigemptyset(&sst);  sigaddset(&sst, SIGCHLD);  sigaddset(&sst, SIGTERM);  addrlen = sizeof(struct sockaddr_in);  sigprocmask(SIG_UNBLOCK, &sst, NULL);	/* enable child signal */  nfd = accept(lfd, (struct sockaddr *) &addr, &addrlen);  sigprocmask(SIG_BLOCK, &sst, NULL);	/* disable child signal */  if (nfd < 0) {    return -1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -