📄 tftpd.c
字号:
(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &flag, sizeof(int)) < 0) { perror("setsockopt(SO_REUSEADDR)"); }#ifdef ENABLE_IPV6 if(!use_ipv6) {#endif me.sin_family = AF_INET; me.sin_addr.s_addr = INADDR_ANY; me.sin_port = htons(port); rc = bind(sock, (struct sockaddr *) &me, sizeof(me));#ifdef ENABLE_IPV6 } else { memset(&me6, 0, sizeof(struct sockaddr_in6)); me6.sin6_family = AF_INET6; me6.sin6_addr = in6addr_any; me6.sin6_port = htons(port); rc = bind(sock, (struct sockaddr *) &me6, sizeof(me6)); }#endif /* ENABLE_IPV6 */ if(rc < 0) { perror("binding stream socket"); logmsg("Error binding socket"); return 1; } pidfile = fopen(pidname, "w"); if(pidfile) { fprintf(pidfile, "%d\n", (int)getpid()); fclose(pidfile); } else { error = ERRNO; logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", pidname); logmsg("Couldn't write pid file"); } logmsg("Running IPv%d version on port UDP/%d",#ifdef ENABLE_IPV6 (use_ipv6?6:4)#else 4#endif , port ); do { fromlen = sizeof(from); n = recvfrom(sock, buf, sizeof (buf), 0, (struct sockaddr *)&from, &fromlen); if (n < 0) { logmsg("recvfrom:\n"); return 3; } from.sin_family = AF_INET; peer = socket(AF_INET, SOCK_DGRAM, 0); if (peer < 0) { logmsg("socket:\n"); return 2; } if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) { logmsg("connect: fail\n"); return 1; } maxtimeout = 5*TIMEOUT; tp = (struct tftphdr *)buf; tp->th_opcode = ntohs(tp->th_opcode); if (tp->th_opcode == RRQ || tp->th_opcode == WRQ) { memset(&test, 0, sizeof(test)); if (tftp(&test, tp, n) < 0) break; if(test.buffer) free(test.buffer); } sclose(peer); } while(1); return 0;}struct formats { const char *f_mode; int f_convert;} formats[] = { { "netascii", 1 }, { "octet", 0 }, { NULL, 0 }};/* * Handle initial connection protocol. */static int tftp(struct testcase *test, struct tftphdr *tp, int size){ char *cp; int first = 1, ecode; struct formats *pf; char *filename, *mode = NULL; int error; FILE *server; /* Open request dump file. */ server = fopen(REQUEST_DUMP, "ab"); if(!server) { error = ERRNO; logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", REQUEST_DUMP); return -1; } /* store input protocol */ fprintf(server, "opcode: %x\n", tp->th_opcode); cp = (char *)&tp->th_stuff; filename = cp;again: while (cp < buf + size) { if (*cp == '\0') break; cp++; } if (*cp) { nak(EBADOP); fclose(server); return 3; } if (first) { mode = ++cp; first = 0; goto again; } /* store input protocol */ fprintf(server, "filename: %s\n", filename); for (cp = mode; *cp; cp++) if(ISUPPER(*cp)) *cp = (char)tolower((int)*cp); /* store input protocol */ fprintf(server, "mode: %s\n", mode); fclose(server); for (pf = formats; pf->f_mode; pf++) if (strcmp(pf->f_mode, mode) == 0) break; if (!pf->f_mode) { nak(EBADOP); return 2; } ecode = validate_access(test, filename, tp->th_opcode); if (ecode) { nak(ecode); return 1; } if (tp->th_opcode == WRQ) recvtftp(test, pf); else sendtftp(test, pf); return 0;}/* * Validate file access. */static int validate_access(struct testcase *test, const char *filename, int mode){ char *ptr; long testno, partno; int error; char partbuf[80]="data"; logmsg("trying to get file: %s mode %x", filename, mode); if(!strncmp("verifiedserver", filename, 15)) { char weare[128]; size_t count = sprintf(weare, "WE ROOLZ: %d\r\n", (int)getpid()); logmsg("Are-we-friendly question received"); test->buffer = strdup(weare); test->rptr = test->buffer; /* set read pointer */ test->bufsize = count; /* set total count */ test->rcount = count; /* set data left to read */ return 0; /* fine */ } /* find the last slash */ ptr = strrchr(filename, '/'); if(ptr) { char *file; ptr++; /* skip the slash */ /* skip all non-numericals following the slash */ while(*ptr && !ISDIGIT(*ptr)) ptr++; /* get the number */ testno = strtol(ptr, &ptr, 10); if(testno > 10000) { partno = testno % 10000; testno /= 10000; } else partno = 0; logmsg("requested test number %ld part %ld", testno, partno); test->num = testno; file = test2file(testno); if(0 != partno) sprintf(partbuf, "data%ld", partno); if(file) { FILE *stream=fopen(file, "rb"); if(!stream) { error = ERRNO; logmsg("fopen() failed with error: %d %s", error, strerror(error)); logmsg("Error opening file: %s", file); logmsg("Couldn't open test file: %s", file); return EACCESS; } else { size_t count; test->buffer = (char *)spitout(stream, "reply", partbuf, &count); fclose(stream); if(test->buffer) { test->rptr = test->buffer; /* set read pointer */ test->bufsize = count; /* set total count */ test->rcount = count; /* set data left to read */ } else return EACCESS; } } else return EACCESS; } else { logmsg("no slash found in path"); return EACCESS; /* failure */ } return 0;}int timeout;#ifdef HAVE_SIGSETJMPsigjmp_buf timeoutbuf;#endifstatic void timer(int signum){ (void)signum; logmsg("alarm!"); timeout += rexmtval; if (timeout >= maxtimeout) exit(1);#ifdef HAVE_SIGSETJMP siglongjmp(timeoutbuf, 1);#endif}/* * Send the requested file. */static void sendtftp(struct testcase *test, struct formats *pf){ struct tftphdr *dp; struct tftphdr *ap; /* ack packet */ unsigned short block = 1; int size; ssize_t n;#if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, timer);#endif dp = r_init(); ap = (struct tftphdr *)ackbuf; do { size = readit(test, &dp, pf->f_convert); if (size < 0) { nak(ERRNO + 100); return; } dp->th_opcode = htons((u_short)DATA); dp->th_block = htons((u_short)block); timeout = 0;#ifdef HAVE_SIGSETJMP (void) sigsetjmp(timeoutbuf, 1);#endif send_data: if (swrite(peer, dp, size + 4) != size + 4) { logmsg("write\n"); return; } read_ahead(test, pf->f_convert); for ( ; ; ) {#ifdef HAVE_ALARM alarm(rexmtval); /* read the ack */#endif n = sread(peer, ackbuf, sizeof (ackbuf));#ifdef HAVE_ALARM alarm(0);#endif if (n < 0) { logmsg("read: fail\n"); return; } ap->th_opcode = ntohs((u_short)ap->th_opcode); ap->th_block = ntohs((u_short)ap->th_block); if (ap->th_opcode == ERROR) { logmsg("got ERROR"); return; } if (ap->th_opcode == ACK) { if (ap->th_block == block) { break; } /* Re-synchronize with the other side */ (void) synchnet(peer); if (ap->th_block == (block -1)) { goto send_data; } } } block++; } while (size == SEGSIZE);}static void justtimeout(int signum){ (void)signum;}/* * Receive a file. */static void recvtftp(struct testcase *test, struct formats *pf){ struct tftphdr *dp; struct tftphdr *ap; /* ack buffer */ unsigned short block = 0; ssize_t n, size;#if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, timer);#endif dp = w_init(); ap = (struct tftphdr *)ackbuf; do { timeout = 0; ap->th_opcode = htons((u_short)ACK); ap->th_block = htons((u_short)block); block++;#ifdef HAVE_SIGSETJMP (void) sigsetjmp(timeoutbuf, 1);#endifsend_ack: if (swrite(peer, ackbuf, 4) != 4) { logmsg("write: fail\n"); goto abort; } write_behind(test, pf->f_convert); for ( ; ; ) {#ifdef HAVE_ALARM alarm(rexmtval);#endif n = sread(peer, dp, PKTSIZE);#ifdef HAVE_ALARM alarm(0);#endif if (n < 0) { /* really? */ logmsg("read: fail\n"); goto abort; } dp->th_opcode = ntohs((u_short)dp->th_opcode); dp->th_block = ntohs((u_short)dp->th_block); if (dp->th_opcode == ERROR) goto abort; if (dp->th_opcode == DATA) { if (dp->th_block == block) { break; /* normal */ } /* Re-synchronize with the other side */ (void) synchnet(peer); if (dp->th_block == (block-1)) goto send_ack; /* rexmit */ } } size = writeit(test, &dp, (int)(n - 4), pf->f_convert); if (size != (n-4)) { /* ahem */ if (size < 0) nak(ERRNO + 100); else nak(ENOSPACE); goto abort; } } while (size == SEGSIZE); write_behind(test, pf->f_convert); ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */ ap->th_block = htons((u_short)(block)); (void) swrite(peer, ackbuf, 4);#if defined(HAVE_ALARM) && defined(SIGALRM) mysignal(SIGALRM, justtimeout); /* just abort read on timeout */ alarm(rexmtval);#endif n = sread(peer, buf, sizeof(buf)); /* normally times out and quits */#ifdef HAVE_ALARM alarm(0);#endif if (n >= 4 && /* if read some data */ dp->th_opcode == DATA && /* and got a data block */ block == dp->th_block) { /* then my last ack was lost */ (void) swrite(peer, ackbuf, 4); /* resend final ack */ }abort: return;}struct errmsg { int e_code; const char *e_msg;} errmsgs[] = { { EUNDEF, "Undefined error code" }, { ENOTFOUND, "File not found" }, { EACCESS, "Access violation" }, { ENOSPACE, "Disk full or allocation exceeded" }, { EBADOP, "Illegal TFTP operation" }, { EBADID, "Unknown transfer ID" }, { EEXISTS, "File already exists" }, { ENOUSER, "No such user" }, { -1, 0 }};/* * Send a nak packet (error message). Error code passed in is one of the * standard TFTP codes, or a UNIX errno offset by 100. */static void nak(int error){ struct tftphdr *tp; int length; struct errmsg *pe; tp = (struct tftphdr *)buf; tp->th_opcode = htons((u_short)ERROR); tp->th_code = htons((u_short)error); for (pe = errmsgs; pe->e_code >= 0; pe++) if (pe->e_code == error) break; if (pe->e_code < 0) { pe->e_msg = strerror(error - 100); tp->th_code = EUNDEF; /* set 'undef' errorcode */ } strcpy(tp->th_msg, pe->e_msg); length = (int)strlen(pe->e_msg); tp->th_msg[length] = '\0'; length += 5; if (swrite(peer, buf, length) != length) logmsg("nak: fail\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -