📄 rinetd.c
字号:
sizeof(SOCKET) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&coInputRPos, sizeof(int) * o, sizeof(int) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&coInputWPos, sizeof(int) * o, sizeof(int) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&coOutputRPos, sizeof(int) * o, sizeof(int) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&coOutputWPos, sizeof(int) * o, sizeof(int) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&coClosed, sizeof(int) * o, sizeof(int) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&coClosing, sizeof(int) * o, sizeof(int) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&reClosed, sizeof(int) * o, sizeof(int) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&loClosed, sizeof(int) * o, sizeof(int) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&coLog, sizeof(int) * o, sizeof(int) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&coSe, sizeof(int) * o, sizeof(int) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&coBytesInput, sizeof(int) * o, sizeof(int) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&reAddresses, 4 * o, 4 * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&coBytesOutput, sizeof(int) * o, sizeof(int) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&coInput, sizeof(char *) * o, sizeof(char *) * coTotal)) { goto shortage; } if (!SAFE_REALLOC(&coOutput, sizeof(char *) * o, sizeof(char *) * coTotal)) { goto shortage; } for (j = o; (j < coTotal); j++) { coClosed[j] = 1; coInput[j] = (char *) malloc(sizeof(char) * bufferSpace); if (!coInput[j]) { int k; for (k = o; (k < j); k++) { free(coInput[k]); free(coOutput[k]); } goto shortage; } coOutput[j] = (char *) malloc(sizeof(char) * bufferSpace); if (!coOutput[j]) { int k; free(coInput[j]); for (k = o; (k < j); k++) { free(coInput[k]); free(coOutput[k]); } goto shortage; } } index = o; } coInputRPos[index] = 0; coInputWPos[index] = 0; coOutputRPos[index] = 0; coOutputWPos[index] = 0; coClosed[index] = 0; coClosing[index] = 0; reClosed[index] = 0; loClosed[index] = 0; reFds[index] = nfd; coBytesInput[index] = 0; coBytesOutput[index] = 0; coLog[index] = 0; coSe[index] = i; sin = (struct sockaddr_in *) &addr; memcpy(address, &(sin->sin_addr.s_addr), 4); memcpy(reAddresses + index * 4, address, 4); /* Now, do we want to accept this connection? Format it for comparison to a pattern. */ sprintf(addressText, "%d.%d.%d.%d", address[0], address[1], address[2], address[3]); /* 1. Check global allow rules. If there are no global allow rules, it's presumed OK at this step. If there are any, and it doesn't match at least one, kick it out. */ if (globalAllowRules) { int good = 0; for (j = 0; (j < globalAllowRules); j++) { if (match(addressText, allowRules[j])) { good = 1; break; } } if (!good) { refuse(index, logNotAllowed); return; } } /* 2. Check global deny rules. If it matches any of the global deny rules, kick it out. */ if (globalDenyRules) { for (j = 0; (j < globalDenyRules); j++) { if (match(addressText, denyRules[j])) { refuse(index, logDenied); } } } /* 3. Check allow rules specific to this forwarding rule. If there are none, it's OK. If there are any, it must match at least one. */ if (seAllowRulesTotal[i]) { int good = 0; for (j = 0; (j < seAllowRulesTotal[i]); j++) { if (match(addressText, allowRules[seAllowRules[i] + j])) { good = 1; break; } } if (!good) { refuse(index, logNotAllowed); return; } } /* 2. Check deny rules specific to this forwarding rule. If it matches any of the deny rules, kick it out. */ if (seDenyRulesTotal[i]) { for (j = 0; (j < seDenyRulesTotal[i]); j++) { if (match(addressText, denyRules[seDenyRules[i] + j])) { refuse(index, logDenied); } } } /* Now open a connection to the local server. This, too, is nonblocking. Why wait for anything when you don't have to? */ openLocalFd(i, index); return;shortage: fprintf(stderr, "rinetd: not enough memory to " "add slots. Currently %d slots.\n", o); /* Go back to the previous total number of slots */ coTotal = o; }void openLocalFd(int se, int i){ int j; struct sockaddr_in saddr; loFds[i] = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (loFds[i] == INVALID_SOCKET) { closesocket(reFds[i]); reClosed[i] = 1; loClosed[i] = 1; coClosed[i] = 1; log(i, coSe[i], logLocalSocketFailed); return; }#ifndef WIN32
if (loFds[i] > maxfd) { maxfd = loFds[i]; }#endif /* WIN32 */
/* Bind the local socket */ saddr.sin_family = AF_INET; saddr.sin_port = INADDR_ANY; saddr.sin_addr.s_addr = 0; if (bind(loFds[i], (struct sockaddr *) &saddr, sizeof(saddr)) == SOCKET_ERROR) { closesocket(loFds[i]); closesocket(reFds[i]); reClosed[i] = 1; loClosed[i] = 1; coClosed[i] = 1; log(i, coSe[i], logLocalBindFailed); return; } memset(&saddr, 0, sizeof(struct sockaddr_in)); saddr.sin_family = AF_INET; memcpy(&saddr.sin_addr, &seLocalAddrs[se], sizeof(struct in_addr)); saddr.sin_port = seLocalPorts[se];#ifndef WIN32
#ifdef LINUX j = 0; setsockopt(loFds[i], SOL_SOCKET, SO_LINGER, &j, sizeof(j));#else j = 1024; setsockopt(loFds[i], SOL_SOCKET, SO_SNDBUF, &j, sizeof(j));#endif /* LINUX */#endif /* WIN32 */
j = 1;
ioctlsocket(loFds[i], FIONBIO, &j);
if (connect(loFds[i], (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)) == INVALID_SOCKET) { if ((GetLastError() != WSAEINPROGRESS) &&
(GetLastError() != WSAEWOULDBLOCK))
{ PERROR("rinetd: connect"); closesocket(loFds[i]); closesocket(reFds[i]); reClosed[i] = 1; loClosed[i] = 1; coClosed[i] = 1; log(i, coSe[i], logLocalConnectFailed); return; } }}int getAddress(char *host, struct in_addr *iaddr){ char *p = host; int ishost = 0; while (*p) { if (!(isdigit(*p) || ((*p) == '.'))) { ishost = 1; break; } p++; } if (ishost) { struct hostent *h; h = gethostbyname(host); if (!h) { return 0; } memcpy( (void *) &iaddr->s_addr, (void *) h->h_addr, 4); return 1; } else { iaddr->s_addr = inet_addr(host); return 1; }}
#ifndef WIN32void plumber(int s){ /* Just reinstall */ signal(SIGPIPE, plumber);}void hup(int s){ /* Learn the new rules */ readConfiguration(); /* And reinstall the signal handler */ signal(SIGHUP, hup);}#endif /* WIN32 */
int safeRealloc(void **data, int oldsize, int newsize){ void *newData = malloc(newsize + 1); if (!newData) { return 0; } if (newsize < oldsize) { memcpy(newData, *data, newsize); } else { memcpy(newData, *data, oldsize); } *data = newData; return 1;}void RegisterPID(void){ FILE *pid_file; char *pid_file_name = "/var/run/rinetd.pid"; if (pidLogFileName) { pid_file_name = pidLogFileName; }/* add other systems with wherever they register processes */#if defined(LINUX) pid_file = fopen(pid_file_name, "w"); if (pid_file == NULL) { /* non-fatal, non-Linux may lack /var/run... */ fprintf(stderr, "rinetd: Couldn't write to " "%s. PID was not logged.\n", pid_file_name); } else { /* error checking deliberately omitted */ fprintf(pid_file, "%d\n", getpid()); fclose(pid_file); }#endif /* LINUX */}unsigned char nullAddress[4] = { 0, 0, 0, 0 };struct tm *get_gmtoff(int *tz);void log(int i, int coSe, int result){ unsigned char *reAddress; int bytesOutput; int bytesInput; /* Bit of borrowing from Apache logging module here, thanks folks */ int timz; struct tm *t; char tstr[1024]; char sign; if (!log) { return; } t = get_gmtoff(&timz); sign = (timz < 0 ? '-' : '+'); if (timz < 0) { timz = -timz; } strftime(tstr, sizeof(tstr), "%d/%b/%Y:%H:%M:%S ", t); if (i != -1) { reAddress = reAddresses + i * 4; bytesOutput = coBytesOutput[i]; bytesInput = coBytesInput[i]; } else { reAddress = nullAddress; bytesOutput = 0; bytesInput = 0; } if (logFile) { if (logFormatCommon) { /* Fake a common log format log file in a way that most web analyzers can do something interesting with. We lie and say the protocol is HTTP because we don't want the web analyzer to reject the line. We also lie and claim success (code 200) because we don't want the web analyzer to ignore the line as an error and not analyze the "URL." We put a result message into our "URL" instead. The last field is an extra, giving the number of input bytes, after several placeholders meant to fill the positions frequently occupied by user agent, referrer, and server name information. */ fprintf(logFile, "%d.%d.%d.%d - - " "[%s %c%.2d%.2d] " "\"GET /rinetd-services/%s/%d/%s/%d/%s HTTP/1.0\" " "200 %d - - - %d\n", reAddress[0], reAddress[1], reAddress[2], reAddress[3], tstr, sign, timz / 60, timz % 60, seFromHosts[coSe], seFromPorts[coSe], seToHosts[coSe], seToPorts[coSe], logMessages[result], bytesOutput, bytesInput); } else { /* Write an rinetd-specific log entry with a less goofy format. */ fprintf(logFile, "%s\t%d.%d.%d.%d\t%s\t%d\t%s\t%d\t%d" "\t%d\t%s\n", tstr, reAddress[0], reAddress[1], reAddress[2], reAddress[3], seFromHosts[coSe], seFromPorts[coSe], seToHosts[coSe], seToPorts[coSe], bytesInput, bytesOutput, logMessages[result]); } }}int readArgs (int argc, char **argv, RinetdOptions *options){ int c; while (1) { int option_index = 0; static struct option long_options[] = { {"conf-file", 1, 0, 'c'}, {"help", 0, 0, 'h'}, {"version", 0, 0, 'v'}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "c:shv", long_options, &option_index); if (c == -1) { break; } switch (c) { case 'c': options->conf_file = malloc(strlen(optarg) + 1); if (!options->conf_file) { fprintf(stderr, "Not enough memory to " "launch rinetd.\n"); exit(1); } strcpy(options->conf_file, optarg); break; case 'h': printf("Usage: rinetd [OPTION]\n" " -c, --conf-file FILE read configuration " "from FILE\n" " -h, --help display this help\n" " -v, --version display version " "number\n\n"); printf("Most options are controlled through the\n" "configuration file. See the rinetd(8)\n" "manpage for more information.\n"); exit (0); case 'v': printf ("rinetd %s\n", VERSION); exit (0); case '?': default: exit (1); } }
return 0;}/* get_gmtoff was borrowed from Apache. Thanks folks. */struct tm *get_gmtoff(int *tz) { time_t tt = time(NULL); struct tm gmt; struct tm *t; int days, hours, minutes; /* Assume we are never more than 24 hours away. */ gmt = *gmtime(&tt); /* remember gmtime/localtime return ptr to static */ t = localtime(&tt); /* buffer... so be careful */ days = t->tm_yday - gmt.tm_yday; hours = ((days < -1 ? 24 : 1 < days ? -24 : days * 24) + t->tm_hour - gmt.tm_hour); minutes = hours * 60 + t->tm_min - gmt.tm_min; *tz = minutes; return t;}int patternBad(char *pattern){ char *p = pattern; while (*p) { if (isdigit(*p) || ((*p) == '?') || ((*p) == '*') || ((*p) == '.')) { p++; } return 0; } return 1;}void refuse(int index, int logCode){ closesocket(reFds[index]); reClosed[index] = 1; loClosed[index] = 1; coClosed[index] = 1; log(index, coSe[index], logCode);}void term(int s){ /* Obey the request, but first flush the log */ if (logFile) { fclose(logFile); } exit(0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -