Changeset 41970 in vbox
- Timestamp:
- Jun 29, 2012 5:55:17 AM (13 years ago)
- Location:
- trunk/src/VBox/Devices/Network/slirp
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Network/slirp/ctl.h
r40286 r41970 25 25 #define CTL_BROADCAST 255 26 26 27 #define CTL_CHECK(x, ctl) ( (RT_N2H_U32((x)) & ~pData->netmask) == (ctl) \27 #define CTL_CHECK(x, ctl) ( ((RT_N2H_U32((x)) & ~pData->netmask) == (ctl)) \ 28 28 && (((x) & RT_H2N_U32(pData->netmask)) == pData->special_addr.s_addr)) -
trunk/src/VBox/Devices/Network/slirp/slirp_state.h
r41453 r41970 48 48 49 49 /** TFTP session entry. */ 50 struct tftp_session 51 { 52 int in_use; 53 unsigned char filename[TFTP_FILENAME_MAX]; 54 55 struct in_addr client_ip; 56 u_int16_t client_port; 57 58 int timestamp; 59 uint64_t u64Offset; 60 }; 50 typedef enum ENMTFTPSESSIONFMT 51 { 52 TFTPFMT_NONE = 0, 53 TFTPFMT_OCTET, 54 TFTPFMT_NETASCII, 55 TFTPFMT_MAIL, 56 TFTPFMT_NOT_FMT = 0xffff 57 } ENMTFTPSESSIONFMT; 58 59 typedef struct TFTPSESSION 60 { 61 int fInUse; 62 unsigned char pszFilename[TFTP_FILENAME_MAX]; 63 struct in_addr IpClientAddress; 64 uint16_t u16ClientPort; 65 int iTimestamp; 66 ENMTFTPSESSIONFMT enmTftpFmt; 67 uint16_t u16BlkSize; 68 uint16_t u16TSize; 69 uint16_t u16Size; 70 uint16_t u16Timeout; 71 } TFTPSESSION, *PTFTPSESSION; 72 73 typedef const PTFTPSESSION PCTFTPSESSION; 61 74 62 75 struct dns_domain_entry … … 183 196 int tcp_reass_overflows; 184 197 /* Stuff from tftp.c */ 185 struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];198 TFTPSESSION aTftpSessions[TFTP_SESSIONS_MAX]; 186 199 const char *tftp_prefix; 187 200 /* Stuff from udp.c */ … … 399 412 #define tcp_now pData->tcp_now 400 413 401 #define tftp_sessions pData->tftp_sessions402 414 #define tftp_prefix pData->tftp_prefix 403 415 -
trunk/src/VBox/Devices/Network/slirp/tftp.c
r40121 r41970 43 43 44 44 #include <slirp.h> 45 46 47 static void tftp_session_update(PNATState pData, struct tftp_session *spt) 48 { 49 spt->timestamp = curtime; 50 spt->in_use = 1; 51 } 52 53 static void tftp_session_terminate(struct tftp_session *spt) 54 { 55 spt->in_use = 0; 56 } 57 58 static int tftp_session_allocate(PNATState pData, struct tftp_t *tp) 59 { 60 struct tftp_session *spt; 45 #include <iprt/file.h> 46 #include <iprt/asm-math.h> 47 48 typedef struct TFTPOPTIONDESC 49 { 50 const char *pszName; 51 ENMTFTPSESSIONFMT enmType; 52 int cbName; 53 bool fHasValue; 54 } TFTPOPTIONDESC, *PTFTPOPTIONDESC; 55 56 typedef const PTFTPOPTIONDESC PCTFTPOPTIONDESC; 57 static TFTPOPTIONDESC g_TftpTransferFmtDesc[] = 58 { 59 {"octet", TFTPFMT_OCTET, 5, false}, /* RFC1350 */ 60 {"netascii", TFTPFMT_NETASCII, 8, false}, /* RFC1350 */ 61 {"mail", TFTPFMT_MAIL, 4, false}, /* RFC1350 */ 62 }; 63 64 static TFTPOPTIONDESC g_TftpDesc[] = 65 { 66 {"blksize", TFTPFMT_NOT_FMT, 7, true}, /* RFC2348 */ 67 {"timeout", TFTPFMT_NOT_FMT, 7, true}, /* RFC2349 */ 68 {"tsize", TFTPFMT_NOT_FMT, 5, true}, /* RFC2349 */ 69 {"size", TFTPFMT_NOT_FMT, 4, true}, /* RFC2349 */ 70 }; 71 72 static uint16_t g_au16RFC2348TftpSessionBlkSize[] = 73 { 74 512, 75 1024, 76 1428, 77 2048, 78 4096, 79 8192 80 }; 81 82 /** 83 * This function evaluate file name. 84 * @param pu8Payload 85 * @param cbPayload 86 * @param cbFileName 87 * @return VINF_SUCCESS - 88 * VERR_INVALID_PARAMETER - 89 */ 90 DECLINLINE(int) tftpSecurityFilenameCheck(PNATState pData, PCTFTPSESSION pcTftpSession) 91 { 92 int cbSessionFilename = 0; 93 int rc = VINF_SUCCESS; 94 AssertPtrReturn(pcTftpSession, VERR_INVALID_PARAMETER); 95 cbSessionFilename = RTStrNLen((const char *)pcTftpSession->pszFilename, TFTP_FILENAME_MAX); 96 if ( !RTStrNCmp((const char*)pcTftpSession->pszFilename, "../", 3) 97 || (pcTftpSession->pszFilename[cbSessionFilename - 1] == '/') 98 || RTStrStr((const char *)pcTftpSession->pszFilename, "/../")) 99 rc = VERR_FILE_NOT_FOUND; 100 101 /* only allow exported prefixes */ 102 if ( RT_SUCCESS(rc) 103 && !tftp_prefix) 104 rc = VERR_INTERNAL_ERROR; 105 LogFlowFuncLeaveRC(rc); 106 return rc; 107 } 108 109 /* 110 * This function returns index of option descriptor in passed descriptor array 111 * @param piIdxOpt returned index value 112 * @param paTftpDesc array of known Tftp descriptors 113 * @param caTftpDesc size of array of tftp descriptors 114 * @param pszOpt name of option 115 */ 116 DECLINLINE(int) tftpFindDesciptorIndexByName(int *piIdxOpt, PCTFTPOPTIONDESC paTftpDesc, int caTftpDesc, const char *pszOptName) 117 { 118 int rc = VINF_SUCCESS; 119 int idxOption = 0; 120 AssertReturn(piIdxOpt, VERR_INVALID_PARAMETER); 121 AssertReturn(paTftpDesc, VERR_INVALID_PARAMETER); 122 AssertReturn(pszOptName, VERR_INVALID_PARAMETER); 123 for (idxOption = 0; idxOption < caTftpDesc; ++idxOption) 124 { 125 if (!RTStrNICmp(pszOptName, paTftpDesc[idxOption].pszName, 10)) 126 { 127 *piIdxOpt = idxOption; 128 return rc; 129 } 130 } 131 rc = VERR_NOT_FOUND; 132 return rc; 133 } 134 135 /** 136 * Helper function to look for index of descriptor in transfer format descriptors 137 * @param piIdxOpt returned value of index 138 * @param pszOpt name of option 139 */ 140 DECLINLINE(int) tftpFindTransferFormatIdxbyName(int *piIdxOpt, const char *pszOpt) 141 { 142 return tftpFindDesciptorIndexByName(piIdxOpt, &g_TftpTransferFmtDesc[0], RT_ELEMENTS(g_TftpTransferFmtDesc), pszOpt); 143 } 144 145 /** 146 * Helper function to look for index of descriptor in options descriptors 147 * @param piIdxOpt returned value of index 148 * @param pszOpt name of option 149 */ 150 DECLINLINE(int) tftpFindOptionIdxbyName(int *piIdxOpt, const char *pszOpt) 151 { 152 return tftpFindDesciptorIndexByName(piIdxOpt, &g_TftpDesc[0], RT_ELEMENTS(g_TftpDesc), pszOpt); 153 } 154 155 156 DECLINLINE(bool) tftpIsAcceptableOption(const char *pszOptionName) 157 { 158 int idxOptDesc = 0; 159 AssertPtrReturn(pszOptionName, false); 160 AssertReturn(RTStrNLen(pszOptionName,10) >= 4, false); 161 AssertReturn(RTStrNLen(pszOptionName,10) < 8, false); 162 for(idxOptDesc = 0; idxOptDesc < RT_ELEMENTS(g_TftpTransferFmtDesc); ++idxOptDesc) 163 { 164 if (!RTStrNICmp(pszOptionName, g_TftpTransferFmtDesc[idxOptDesc].pszName, 10)) 165 return true; 166 } 167 for(idxOptDesc = 0; idxOptDesc < RT_ELEMENTS(g_TftpDesc); ++idxOptDesc) 168 { 169 if (!RTStrNICmp(pszOptionName, g_TftpDesc[idxOptDesc].pszName, 10)) 170 return true; 171 } 172 return false; 173 } 174 175 /** 176 * This function returns the tftp transfer mode 177 * @param pTftpIpHeader header of tftp (includes IP, UDP and TFTP) it's required for validating that buffer comming 178 * in pcu8Options is comes right after header. 179 * @param pcu8Options pointer to options buffer 180 * @param cbOptions size of the options buffer 181 */ 182 DECLINLINE(char *) tftpOptionMode(PCTFTPIPHDR pTftpIpHeader, const uint8_t *pcu8Options, int cbOptions) 183 { 184 int idxOptDesc = 0; 185 AssertPtrReturn(pTftpIpHeader, NULL); 186 AssertPtrReturn(pcu8Options, NULL); 187 AssertReturn(cbOptions >= 4, NULL); 188 /* @todo validate that Mode Option just after filename of TFTP */ 189 for (idxOptDesc = 0; idxOptDesc < RT_ELEMENTS(g_TftpTransferFmtDesc); ++idxOptDesc) 190 { 191 if (!RTStrNICmp(g_TftpTransferFmtDesc[idxOptDesc].pszName, (const char *)pcu8Options, cbOptions)) 192 return (char *)g_TftpTransferFmtDesc[idxOptDesc].pszName; 193 } 194 return NULL; 195 } 196 197 /** 198 * This helper function that validate if client want to operate in supported by server mode. 199 * @param pcTftpHeader comulative header (IP, UDP, TFTP) 200 * @param pcu8Options pointer to the options supposing that pointer points at the mode option 201 * @param cbOptions size of the options buffer 202 */ 203 DECLINLINE(int) tftpIsSupportedTransferMode(PCTFTPSESSION pcTftpSession) 204 { 205 AssertPtrReturn(pcTftpSession, 0); 206 return (pcTftpSession->enmTftpFmt == TFTPFMT_OCTET); 207 } 208 209 210 DECLINLINE(void) tftpSessionUpdate(PNATState pData, PTFTPSESSION pTftpSession) 211 { 212 pTftpSession->iTimestamp = curtime; 213 pTftpSession->fInUse = 1; 214 } 215 216 DECLINLINE(void) tftpSessionTerminate(PTFTPSESSION pTftpSession) 217 { 218 pTftpSession->fInUse = 0; 219 } 220 221 DECLINLINE(int) tftpSessionOptionParse(PTFTPSESSION pTftpSession, PCTFTPIPHDR pcTftpIpHeader) 222 { 223 int rc = VINF_SUCCESS; 224 char *pszTftpRRQRaw; 225 int idxTftpRRQRaw = 0; 226 int cbTftpRRQRaw = 0; 227 int fWithArg = 0; 228 int idxOptionArg = 0; 229 AssertPtrReturn(pTftpSession, VERR_INVALID_PARAMETER); 230 AssertPtrReturn(pcTftpIpHeader, VERR_INVALID_PARAMETER); 231 AssertReturn(RT_N2H_U16(pcTftpIpHeader->u16TftpOpType) == TFTP_RRQ, VERR_INVALID_PARAMETER); 232 LogFlowFunc(("pTftpSession:%p, pcTftpIpHeader:%p\n", pTftpSession, pcTftpIpHeader)); 233 pszTftpRRQRaw = (char *)&pcTftpIpHeader->Core; 234 cbTftpRRQRaw = RT_H2N_U16(pcTftpIpHeader->UdpHdr.uh_ulen) + sizeof(struct ip) - RT_OFFSETOF(TFTPIPHDR, Core); 235 while(cbTftpRRQRaw) 236 { 237 idxTftpRRQRaw = RTStrNLen(pszTftpRRQRaw, 512 - idxTftpRRQRaw) + 1; 238 if (RTStrNLen((char *)pTftpSession->pszFilename, TFTP_FILENAME_MAX) == 0) 239 { 240 rc = RTStrCopy((char *)pTftpSession->pszFilename, TFTP_FILENAME_MAX, pszTftpRRQRaw); 241 if (RT_FAILURE(rc)) 242 { 243 LogFlowFuncLeaveRC(rc); 244 AssertRCReturn(rc,rc); 245 } 246 } 247 else if (pTftpSession->enmTftpFmt == TFTPFMT_NONE) 248 { 249 int idxFmt = 0; 250 rc = tftpFindTransferFormatIdxbyName(&idxFmt, pszTftpRRQRaw); 251 if (RT_FAILURE(rc)) 252 { 253 LogFlowFuncLeaveRC(VERR_INTERNAL_ERROR); 254 return VERR_INTERNAL_ERROR; 255 } 256 AssertReturn( g_TftpTransferFmtDesc[idxFmt].enmType != TFTPFMT_NONE 257 && g_TftpTransferFmtDesc[idxFmt].enmType != TFTPFMT_NOT_FMT, VERR_INTERNAL_ERROR); 258 pTftpSession->enmTftpFmt = g_TftpTransferFmtDesc[idxFmt].enmType; 259 } 260 else if (fWithArg) 261 { 262 if (!RTStrICmp("blksize", g_TftpDesc[idxOptionArg].pszName)) 263 rc = RTStrToInt16Full(pszTftpRRQRaw, 0, (int16_t *)&pTftpSession->u16BlkSize); 264 else if (!RTStrICmp("size", g_TftpDesc[idxOptionArg].pszName)) 265 rc = RTStrToInt16Full(pszTftpRRQRaw, 0, (int16_t *)&pTftpSession->u16Size); 266 else if (!RTStrICmp("tsize", g_TftpDesc[idxOptionArg].pszName)) 267 rc = RTStrToInt16Full(pszTftpRRQRaw, 0, (int16_t *)&pTftpSession->u16TSize); 268 else if (!RTStrICmp("timeoute", g_TftpDesc[idxOptionArg].pszName)) 269 rc = RTStrToInt16Full(pszTftpRRQRaw, 0, (int16_t *)&pTftpSession->u16Timeout); 270 else 271 rc = VERR_INVALID_PARAMETER; 272 if (RT_FAILURE(rc)) 273 { 274 LogFlowFuncLeaveRC(rc); 275 AssertRCReturn(rc,rc); 276 } 277 fWithArg = 0; 278 idxOptionArg = 0; 279 } 280 else 281 { 282 rc = tftpFindOptionIdxbyName(&idxOptionArg, pszTftpRRQRaw); 283 if (RT_SUCCESS(rc)) 284 fWithArg = 1; 285 else 286 { 287 LogFlowFuncLeaveRC(rc); 288 AssertRCReturn(rc,rc); 289 } 290 } 291 pszTftpRRQRaw += idxTftpRRQRaw; 292 cbTftpRRQRaw -= idxTftpRRQRaw; 293 } 294 295 LogFlowFuncLeaveRC(rc); 296 return rc; 297 } 298 299 static int tftpAllocateSession(PNATState pData, PCTFTPIPHDR pcTftpIpHeader) 300 { 301 PTFTPSESSION pTftpSession; 302 int rc = VINF_SUCCESS; 303 int idxSession; 304 305 for (idxSession = 0; idxSession < TFTP_SESSIONS_MAX; idxSession++) 306 { 307 pTftpSession = &pData->aTftpSessions[idxSession]; 308 309 if (!pTftpSession->fInUse) 310 goto found; 311 312 /* sessions time out after 5 inactive seconds */ 313 if ((int)(curtime - pTftpSession->iTimestamp) > 5000) 314 goto found; 315 } 316 317 return -1; 318 319 found: 320 memset(pTftpSession, 0, sizeof(*pTftpSession)); 321 memcpy(&pTftpSession->IpClientAddress, &pcTftpIpHeader->IPv4Hdr.ip_src, sizeof(pTftpSession->IpClientAddress)); 322 pTftpSession->u16ClientPort = pcTftpIpHeader->UdpHdr.uh_sport; 323 rc = tftpSessionOptionParse(pTftpSession, pcTftpIpHeader); 324 AssertRCReturn(rc, -1); 325 326 tftpSessionUpdate(pData, pTftpSession); 327 328 return idxSession; 329 } 330 331 static int tftpSessionFind(PNATState pData, PCTFTPIPHDR pcTftpIpHeader) 332 { 333 PTFTPSESSION pTftpSession; 61 334 int k; 62 335 63 336 for (k = 0; k < TFTP_SESSIONS_MAX; k++) 64 337 { 65 spt = &tftp_sessions[k]; 66 67 if (!spt->in_use) 68 goto found; 69 70 /* sessions time out after 5 inactive seconds */ 71 if ((int)(curtime - spt->timestamp) > 5000) 72 goto found; 73 } 74 75 return -1; 76 77 found: 78 memset(spt, 0, sizeof(*spt)); 79 memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip)); 80 spt->client_port = tp->udp.uh_sport; 81 82 tftp_session_update(pData, spt); 83 84 return k; 85 } 86 87 static int tftp_session_find(PNATState pData, struct tftp_t *tp) 88 { 89 struct tftp_session *spt; 90 int k; 91 92 for (k = 0; k < TFTP_SESSIONS_MAX; k++) 93 { 94 spt = &tftp_sessions[k]; 95 96 if (spt->in_use) 97 { 98 if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) 338 pTftpSession = &pData->aTftpSessions[k]; 339 340 if (pTftpSession->fInUse) 341 { 342 if (!memcmp(&pTftpSession->IpClientAddress, &pcTftpIpHeader->IPv4Hdr.ip_src, sizeof(pTftpSession->IpClientAddress))) 99 343 { 100 if ( spt->client_port == tp->udp.uh_sport)344 if (pTftpSession->u16ClientPort == pcTftpIpHeader->UdpHdr.uh_sport) 101 345 return k; 102 346 } … … 107 351 } 108 352 109 static int tftp_read_data(PNATState pData, struct tftp_session *spt, u_int16_t block_nr, 110 u_int8_t *buf, int len) 111 { 112 int fd; 113 int bytes_read = 0; 114 char buffer[1024]; 115 int n; 116 117 n = RTStrPrintf(buffer, sizeof(buffer), "%s/%s", 118 tftp_prefix, spt->filename); 119 if (n >= sizeof(buffer)) 353 DECLINLINE(int) pftpSessionOpenFile(PNATState pData, PTFTPSESSION pTftpSession, PRTFILE pSessionFile) 354 { 355 char aszSessionFileName[TFTP_FILENAME_MAX]; 356 int cbSessionFileName; 357 int rc = VINF_SUCCESS; 358 cbSessionFileName = RTStrPrintf(aszSessionFileName, TFTP_FILENAME_MAX, "%s/%s", 359 tftp_prefix, pTftpSession->pszFilename); 360 if (cbSessionFileName >= TFTP_FILENAME_MAX) 361 { 362 LogFlowFuncLeaveRC(VERR_INTERNAL_ERROR); 363 return VERR_INTERNAL_ERROR; 364 } 365 366 if (!RTFileExists(aszSessionFileName)) 367 { 368 LogFlowFuncLeaveRC(VERR_FILE_NOT_FOUND); 369 return VERR_FILE_NOT_FOUND; 370 } 371 372 rc = RTFileOpen(pSessionFile, aszSessionFileName, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); 373 LogFlowFuncLeaveRC(rc); 374 return rc; 375 } 376 377 /* @todo: rewrite this */ 378 DECLINLINE(int) tftpSessionEvaluateBlkSize(PNATState pData, PTFTPSESSION pTftpSession) 379 { 380 int rc = VINF_SUCCESS; 381 RTFILE hSessionFile; 382 uint64_t cbSessionFile = 0; 383 int idxRFC2348TftpSessionBlkSize = 0; 384 uint32_t cBlockSessionFile = 0; 385 LogFlowFunc(("pTftpSession:%p\n", pTftpSession)); 386 387 rc = pftpSessionOpenFile(pData, pTftpSession, &hSessionFile); 388 if (RT_FAILURE(rc)) 389 { 390 LogFlowFuncLeave(); 391 return rc; 392 } 393 394 rc = RTFileGetSize(hSessionFile, &cbSessionFile); 395 RTFileClose(hSessionFile); 396 if (RT_FAILURE(rc)) 397 { 398 LogFlowFuncLeave(); 399 return rc; 400 } 401 402 if (!pTftpSession->u16BlkSize) 403 { 404 pTftpSession->u16BlkSize = 1428; 405 } 406 cBlockSessionFile = ASMDivU64ByU32RetU32(cbSessionFile, pTftpSession->u16BlkSize); 407 while ( cBlockSessionFile >= UINT16_MAX 408 && idxRFC2348TftpSessionBlkSize <= RT_ELEMENTS(g_au16RFC2348TftpSessionBlkSize)) 409 { 410 if (pTftpSession->u16BlkSize > g_au16RFC2348TftpSessionBlkSize[idxRFC2348TftpSessionBlkSize]) 411 { 412 idxRFC2348TftpSessionBlkSize++; 413 continue; 414 } 415 416 417 idxRFC2348TftpSessionBlkSize++; 418 /* No bigger values in RFC2348 */ 419 AssertReturn(idxRFC2348TftpSessionBlkSize <= RT_ELEMENTS(g_au16RFC2348TftpSessionBlkSize), VERR_INTERNAL_ERROR); 420 if (g_au16RFC2348TftpSessionBlkSize[idxRFC2348TftpSessionBlkSize] >= if_maxlinkhdr) 421 { 422 /* Buffer size is too large for current settings */ 423 rc = VERR_BUFFER_OVERFLOW; 424 LogFlowFuncLeaveRC(rc); 425 } 426 } 427 LogFlowFuncLeaveRC(rc); 428 return rc; 429 } 430 431 DECLINLINE(int) tftpSend(PNATState pData, 432 PTFTPSESSION pTftpSession, 433 struct mbuf *pMBuf, 434 PCTFTPIPHDR pcTftpIpHeaderRecv) 435 { 436 int rc = VINF_SUCCESS; 437 struct sockaddr_in saddr, daddr; 438 LogFlowFunc(("pMBuf:%p, pcTftpIpHeaderRecv:%p\n", pMBuf, pcTftpIpHeaderRecv)); 439 saddr.sin_addr = pcTftpIpHeaderRecv->IPv4Hdr.ip_dst; 440 saddr.sin_port = pcTftpIpHeaderRecv->UdpHdr.uh_dport; 441 442 daddr.sin_addr = pTftpSession->IpClientAddress; 443 daddr.sin_port = pTftpSession->u16ClientPort; 444 445 446 pMBuf->m_data += sizeof(struct udpiphdr); 447 pMBuf->m_len -= sizeof(struct udpiphdr); 448 udp_output2(pData, NULL, pMBuf, &saddr, &daddr, IPTOS_LOWDELAY); 449 LogFlowFuncLeaveRC(rc); 450 return rc; 451 } 452 DECLINLINE(int) tftpSendError(PNATState pData, PTFTPSESSION pTftpSession, uint16_t errorcode, const char *msg, PCTFTPIPHDR pcTftpIpHeaderRecv); 453 454 DECLINLINE(int) tftpReadDataBlock(PNATState pData, 455 PTFTPSESSION pTftpSession, 456 uint16_t u16BlockNr, 457 uint8_t *pu8Data, 458 int *pcbReadData) 459 { 460 RTFILE hSessionFile; 461 int rc = VINF_SUCCESS; 462 LogFlowFunc(("pTftpSession:%p, u16BlockNr:%RX16, pu8Data:%p, pcbReadData:%p\n", 463 pTftpSession, 464 u16BlockNr, 465 pu8Data, 466 pcbReadData)); 467 468 rc = pftpSessionOpenFile(pData, pTftpSession, &hSessionFile); 469 if (RT_FAILURE(rc)) 470 { 471 LogFlowFuncLeaveRC(rc); 472 return rc; 473 } 474 475 if (pcbReadData) 476 { 477 rc = RTFileSeek(hSessionFile, 478 u16BlockNr * pTftpSession->u16BlkSize, 479 RTFILE_SEEK_BEGIN, 480 NULL); 481 if (RT_FAILURE(rc)) 482 { 483 RTFileClose(hSessionFile); 484 LogFlowFuncLeaveRC(rc); 485 return rc; 486 } 487 rc = RTFileRead(hSessionFile, pu8Data, pTftpSession->u16BlkSize, (size_t *)pcbReadData); 488 if (RT_FAILURE(rc)) 489 { 490 RTFileClose(hSessionFile); 491 LogFlowFuncLeaveRC(rc); 492 return rc; 493 } 494 } 495 496 rc = RTFileClose(hSessionFile); 497 498 LogFlowFuncLeaveRC(rc); 499 return rc; 500 } 501 502 DECLINLINE(int) tftpAddOptionToOACK(PNATState pData, struct mbuf *pMBuf, const char *pszOptName, uint16_t u16OptValue) 503 { 504 char aszOptionBuffer[256]; 505 int iOptLength = 0; 506 int rc = VINF_SUCCESS; 507 int cbMBufCurrent = pMBuf->m_len; 508 LogFlowFunc(("pMBuf:%p, pszOptName:%s, u16OptValue:%u\n", pMBuf, pszOptName, u16OptValue)); 509 AssertPtrReturn(pMBuf, VERR_INVALID_PARAMETER); 510 AssertPtrReturn(pszOptName, VERR_INVALID_PARAMETER); 511 512 RT_ZERO(aszOptionBuffer); 513 iOptLength += RTStrPrintf(aszOptionBuffer, 256 , "%s", pszOptName) + 1; 514 iOptLength += RTStrPrintf(aszOptionBuffer + iOptLength, 256 - iOptLength , "%u", u16OptValue) + 1; 515 if (iOptLength > M_TRAILINGSPACE(pMBuf)) 516 rc = VERR_BUFFER_OVERFLOW; /* buffer too small */ 517 else 518 { 519 pMBuf->m_len += iOptLength; 520 m_copyback(pData, pMBuf, cbMBufCurrent, iOptLength, aszOptionBuffer); 521 } 522 LogFlowFuncLeaveRC(rc); 523 return rc; 524 } 525 526 DECLINLINE(int) tftpSendOACK(PNATState pData, 527 PTFTPSESSION pTftpSession, 528 PCTFTPIPHDR pcTftpIpHeaderRecv) 529 { 530 struct mbuf *m; 531 PTFTPIPHDR pTftpIpHeader; 532 int rc = VINF_SUCCESS; 533 534 rc = tftpSessionEvaluateBlkSize(pData, pTftpSession); 535 if (RT_FAILURE(rc)) 536 { 537 tftpSendError(pData, pTftpSession, 2, "Internal Error (blksize evaluation)", pcTftpIpHeaderRecv); 538 LogFlowFuncLeave(); 120 539 return -1; 121 122 fd = open(buffer, O_RDONLY | O_BINARY); 123 if (fd < 0) 124 return -1; 125 126 if (len) 127 { 128 lseek(fd, block_nr * 512, SEEK_SET); 129 bytes_read = read(fd, buf, len); 130 } 131 132 close(fd); 133 134 return bytes_read; 135 } 136 137 static int tftp_send_oack(PNATState pData, 138 struct tftp_session *spt, 139 const char *key, uint32_t value, 140 struct tftp_t *recv_tp) 141 { 142 struct sockaddr_in saddr, daddr; 143 struct mbuf *m; 144 struct tftp_t *tp; 145 int n = 0; 540 } 146 541 147 542 m = slirpTftpMbufAlloc(pData); … … 149 544 return -1; 150 545 546 547 151 548 m->m_data += if_maxlinkhdr; 152 549 m->m_pkthdr.header = mtod(m, void *); 153 tp = (void *)m->m_data; 154 m->m_data += sizeof(struct udpiphdr); 155 156 tp->tp_op = RT_H2N_U16_C(TFTP_OACK); 157 n += RTStrPrintf((char *)tp->x.tp_buf + n, M_TRAILINGSPACE(m), "%s", key) + 1; 158 n += RTStrPrintf((char *)tp->x.tp_buf + n, M_TRAILINGSPACE(m), "%u", value) + 1; 159 160 saddr.sin_addr = recv_tp->ip.ip_dst; 161 saddr.sin_port = recv_tp->udp.uh_dport; 162 163 daddr.sin_addr = spt->client_ip; 164 daddr.sin_port = spt->client_port; 165 166 m->m_len = sizeof(struct tftp_t) - 514 + n - 167 sizeof(struct ip) - sizeof(struct udphdr); 168 udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); 169 170 return 0; 171 } 172 173 static int tftp_send_error(PNATState pData, 174 struct tftp_session *spt, 175 u_int16_t errorcode, const char *msg, 176 struct tftp_t *recv_tp) 177 { 178 struct sockaddr_in saddr, daddr; 179 struct mbuf *m; 180 struct tftp_t *tp; 550 pTftpIpHeader = mtod(m, PTFTPIPHDR); 551 m->m_len = sizeof(TFTPIPHDR) - sizeof(uint16_t); /* no u16TftpOpCode */ 552 553 pTftpIpHeader->u16TftpOpType = RT_H2N_U16_C(TFTP_OACK); 554 555 if (pTftpSession->u16BlkSize) 556 rc = tftpAddOptionToOACK(pData, m, "blksize", pTftpSession->u16BlkSize); 557 if ( RT_SUCCESS(rc) 558 && pTftpSession->u16Size) 559 rc = tftpAddOptionToOACK(pData, m, "size", pTftpSession->u16Size); 560 if ( RT_SUCCESS(rc) 561 && pTftpSession->u16TSize) 562 rc = tftpAddOptionToOACK(pData, m, "tsize", pTftpSession->u16TSize); 563 564 rc = tftpSend(pData, pTftpSession, m, pcTftpIpHeaderRecv); 565 return RT_SUCCESS(rc) ? 0 : -1; 566 } 567 568 DECLINLINE(int) tftpSendError(PNATState pData, 569 PTFTPSESSION pTftpSession, 570 uint16_t errorcode, 571 const char *msg, 572 PCTFTPIPHDR pcTftpIpHeaderRecv) 573 { 574 struct mbuf *m = NULL; 575 PTFTPIPHDR pTftpIpHeader = NULL; 181 576 182 577 m = slirpTftpMbufAlloc(pData); … … 185 580 186 581 m->m_data += if_maxlinkhdr; 582 m->m_len = sizeof(TFTPIPHDR) 583 + strlen(msg) + 1; /* ending zero */ 187 584 m->m_pkthdr.header = mtod(m, void *); 188 tp = (void *)m->m_data; 189 m->m_data += sizeof(struct udpiphdr); 190 191 tp->tp_op = RT_H2N_U16_C(TFTP_ERROR); 192 tp->x.tp_error.tp_error_code = RT_H2N_U16(errorcode); 193 strcpy((char *)tp->x.tp_error.tp_msg, msg); 194 195 saddr.sin_addr = recv_tp->ip.ip_dst; 196 saddr.sin_port = recv_tp->udp.uh_dport; 197 198 daddr.sin_addr = spt->client_ip; 199 daddr.sin_port = spt->client_port; 200 201 m->m_len = sizeof(struct tftp_t) 202 - 514 203 + 3 204 + strlen(msg) 205 - sizeof(struct ip) 206 - sizeof(struct udphdr); 207 208 udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); 209 210 tftp_session_terminate(spt); 585 pTftpIpHeader = mtod(m, PTFTPIPHDR); 586 587 pTftpIpHeader->u16TftpOpType = RT_H2N_U16_C(TFTP_ERROR); 588 pTftpIpHeader->Core.u16TftpOpCode = RT_H2N_U16(errorcode); 589 590 m_copyback(pData, m, sizeof(TFTPIPHDR), strlen(msg) + 1 /* copy ending zerro*/, (c_caddr_t)msg); 591 592 tftpSend(pData, pTftpSession, m, pcTftpIpHeaderRecv); 593 594 tftpSessionTerminate(pTftpSession); 211 595 212 596 return 0; 213 597 } 214 598 215 static int tftp _send_data(PNATState pData,216 struct tftp_session *spt,599 static int tftpSendData(PNATState pData, 600 PTFTPSESSION pTftpSession, 217 601 u_int16_t block_nr, 218 struct tftp_t *recv_tp) 219 { 220 struct sockaddr_in saddr, daddr; 602 PCTFTPIPHDR pcTftpIpHeaderRecv) 603 { 221 604 struct mbuf *m; 222 struct tftp_t *tp;605 PTFTPIPHDR pTftpIpHeader; 223 606 int nobytes; 224 607 int rc = VINF_SUCCESS; 608 609 /* we should be sure that we don't talk about file offset prior 0 ;) */ 225 610 if (block_nr < 1) 226 611 return -1; … … 232 617 m->m_data += if_maxlinkhdr; 233 618 m->m_pkthdr.header = mtod(m, void *); 234 tp = mtod(m, void *); 235 m->m_data += sizeof(struct udpiphdr); 236 237 tp->tp_op = RT_H2N_U16_C(TFTP_DATA); 238 tp->x.tp_data.tp_block_nr = RT_H2N_U16(block_nr); 239 240 saddr.sin_addr = recv_tp->ip.ip_dst; 241 saddr.sin_port = recv_tp->udp.uh_dport; 242 243 daddr.sin_addr = spt->client_ip; 244 daddr.sin_port = spt->client_port; 245 246 nobytes = tftp_read_data(pData, spt, block_nr - 1, tp->x.tp_data.tp_buf, 512); 247 if (nobytes < 0) 619 pTftpIpHeader = mtod(m, PTFTPIPHDR); 620 m->m_len = sizeof(TFTPIPHDR); 621 622 pTftpIpHeader->u16TftpOpType = RT_H2N_U16_C(TFTP_DATA); 623 pTftpIpHeader->Core.u16TftpOpCode = RT_H2N_U16(block_nr); 624 625 rc = tftpReadDataBlock(pData, pTftpSession, block_nr - 1, (uint8_t *)&pTftpIpHeader->Core.u16TftpOpCode + sizeof(uint16_t), &nobytes); 626 627 if (RT_SUCCESS(rc)) 628 { 629 m->m_len += nobytes; 630 tftpSend(pData, pTftpSession, m, pcTftpIpHeaderRecv); 631 if (nobytes > 0) 632 tftpSessionUpdate(pData, pTftpSession); 633 else 634 tftpSessionTerminate(pTftpSession); 635 } 636 else 248 637 { 249 638 m_freem(pData, m); 639 tftpSendError(pData, pTftpSession, 1, "File not found", pcTftpIpHeaderRecv); 250 640 /* send "file not found" error back */ 251 tftp_send_error(pData, spt, 1, "File not found", tp);252 641 return -1; 253 642 } 254 643 255 m->m_len = sizeof(struct tftp_t)256 - (512 - nobytes)257 - sizeof(struct ip)258 - sizeof(struct udphdr);259 260 udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);261 262 if (nobytes == 512)263 tftp_session_update(pData, spt);264 else265 tftp_session_terminate(spt);266 267 644 return 0; 268 645 } 269 646 270 static void tftp_handle_rrq(PNATState pData, struct tftp_t *tp, int pktlen) 271 { 272 struct tftp_session *spt; 273 int s, k, n; 274 u_int8_t *src, *dst; 275 276 s = tftp_session_allocate(pData, tp); 647 DECLINLINE(void) tftpProcessRRQ(PNATState pData, PCTFTPIPHDR pTftpIpHeader, int pktlen) 648 { 649 PTFTPSESSION pTftpSession; 650 int idxTftpSession = 0; 651 uint8_t *pu8Payload = NULL; 652 int cbPayload = 0; 653 int cbFileName = 0; 654 655 AssertPtrReturnVoid(pTftpIpHeader); 656 AssertPtrReturnVoid(pData); 657 AssertReturnVoid(pktlen > sizeof(TFTPIPHDR)); 658 LogFlowFunc(("ENTER: pTftpIpHeader:%p, pktlen:%d\n", pTftpIpHeader, pktlen)); 659 660 idxTftpSession = tftpAllocateSession(pData, pTftpIpHeader); 661 if (idxTftpSession < 0) 662 { 663 LogFlowFuncLeave(); 664 return; 665 } 666 667 pTftpSession = &pData->aTftpSessions[idxTftpSession]; 668 pu8Payload = (uint8_t *)&pTftpIpHeader->Core; 669 cbPayload = pktlen - sizeof(TFTPIPHDR); 670 671 cbFileName = RTStrNLen((char *)pu8Payload, cbPayload); 672 /* We assume that file name should finish with '\0' and shouldn't bigger 673 * than buffer for name storage. 674 */ 675 AssertReturnVoid( cbFileName < cbPayload 676 && cbFileName < TFTP_FILENAME_MAX /* current limit in tftp session handle */ 677 && cbFileName); 678 679 /* Dont't bother with rest processing in case of invalid access */ 680 if (RT_FAILURE(tftpSecurityFilenameCheck(pData, pTftpSession))) 681 { 682 tftpSendError(pData, pTftpSession, 2, "Access violation", pTftpIpHeader); 683 LogFlowFuncLeave(); 684 return; 685 } 686 687 688 689 if (RT_UNLIKELY(!tftpIsSupportedTransferMode(pTftpSession))) 690 { 691 tftpSendError(pData, pTftpSession, 4, "Unsupported transfer mode", pTftpIpHeader); 692 LogFlowFuncLeave(); 693 return; 694 } 695 696 697 tftpSendOACK(pData, pTftpSession, pTftpIpHeader); 698 LogFlowFuncLeave(); 699 return; 700 } 701 702 static void tftpProcessACK(PNATState pData, PTFTPIPHDR pTftpIpHeader) 703 { 704 int s; 705 706 s = tftpSessionFind(pData, pTftpIpHeader); 277 707 if (s < 0) 278 708 return; 279 709 280 spt = &tftp_sessions[s]; 281 282 src = tp->x.tp_buf; 283 dst = spt->filename; 284 n = pktlen - ((uint8_t *)&tp->x.tp_buf[0] - (uint8_t *)tp); 285 286 /* get name */ 287 for (k = 0; k < n; k++) 288 { 289 if (k < TFTP_FILENAME_MAX) 290 dst[k] = src[k]; 291 else 710 if (tftpSendData(pData, &pData->aTftpSessions[s], 711 RT_N2H_U16(pTftpIpHeader->Core.u16TftpOpCode) + 1, pTftpIpHeader) < 0) 712 { 713 /* XXX */ 714 } 715 } 716 717 DECLCALLBACK(void) tftp_input(PNATState pData, struct mbuf *pMbuf) 718 { 719 PTFTPIPHDR pTftpIpHeader = NULL; 720 AssertPtr(pData); 721 AssertPtr(pMbuf); 722 pTftpIpHeader = mtod(pMbuf, PTFTPIPHDR); 723 724 switch(RT_N2H_U16(pTftpIpHeader->u16TftpOpType)) 725 { 726 case TFTP_RRQ: 727 tftpProcessRRQ(pData, pTftpIpHeader, m_length(pMbuf, NULL)); 728 break; 729 730 case TFTP_ACK: 731 tftpProcessACK(pData, pTftpIpHeader); 732 break; 733 default: 734 LogFlowFuncLeave(); 292 735 return; 293 294 if (src[k] == '\0') 295 break; 296 } 297 298 if (k >= n) 299 return; 300 301 k++; 302 303 /* check mode */ 304 if ((n - k) < 6) 305 return; 306 307 if (memcmp(&src[k], "octet\0", 6) != 0) 308 { 309 tftp_send_error(pData, spt, 4, "Unsupported transfer mode", tp); 310 return; 311 } 312 313 k += 6; /* skipping octet */ 314 315 /* do sanity checks on the filename */ 316 if ( !strncmp((const char*)spt->filename, "../", 3) 317 || (spt->filename[strlen((const char *)spt->filename) - 1] == '/') 318 || strstr((const char *)spt->filename, "/../")) 319 { 320 tftp_send_error(pData, spt, 2, "Access violation", tp); 321 return; 322 } 323 324 /* only allow exported prefixes */ 325 if (!tftp_prefix) 326 { 327 tftp_send_error(pData, spt, 2, "Access violation", tp); 328 return; 329 } 330 331 /* check if the file exists */ 332 if (tftp_read_data(pData, spt, 0, spt->filename, 0) < 0) 333 { 334 tftp_send_error(pData, spt, 1, "File not found", tp); 335 return; 336 } 337 338 if (src[n - 1] != 0) 339 { 340 tftp_send_error(pData, spt, 2, "Access violation", tp); 341 return; 342 } 343 344 while (k < n) 345 { 346 const char *key, *value; 347 348 key = (const char *)src + k; 349 k += strlen(key) + 1; 350 351 if (k >= n) 352 { 353 tftp_send_error(pData, spt, 2, "Access violation", tp); 354 return; 355 } 356 357 value = (const char *)src + k; 358 k += strlen(value) + 1; 359 360 if (strcmp(key, "tsize") == 0) 361 { 362 int tsize = atoi(value); 363 struct stat stat_p; 364 365 if (tsize == 0 && tftp_prefix) 366 { 367 char buffer[1024]; 368 int len; 369 370 len = RTStrPrintf(buffer, sizeof(buffer), "%s/%s", 371 tftp_prefix, spt->filename); 372 if (RT_UNLIKELY(len <= 0)) 373 { 374 tftp_send_error(pData, spt, 1, "Filename is invalid", tp); 375 return; 376 } 377 if (stat(buffer, &stat_p) == 0) 378 tsize = stat_p.st_size; 379 else 380 { 381 tftp_send_error(pData, spt, 1, "File not found", tp); 382 return; 383 } 384 } 385 386 tftp_send_oack(pData, spt, "tsize", tsize, tp); 387 return; 388 } 389 } 390 391 tftp_send_data(pData, spt, 1, tp); 392 } 393 394 static void tftp_handle_ack(PNATState pData, struct tftp_t *tp) 395 { 396 int s; 397 398 s = tftp_session_find(pData, tp); 399 if (s < 0) 400 return; 401 402 if (tftp_send_data(pData, &tftp_sessions[s], 403 RT_N2H_U16(tp->x.tp_data.tp_block_nr) + 1, tp) < 0) 404 { 405 /* XXX */ 406 } 407 } 408 409 void tftp_input(PNATState pData, struct mbuf *m) 410 { 411 struct tftp_t *tp = (struct tftp_t *)m->m_data; 412 413 switch(RT_N2H_U16(tp->tp_op)) 414 { 415 case TFTP_RRQ: 416 tftp_handle_rrq(pData, tp, m->m_len); 417 break; 418 419 case TFTP_ACK: 420 tftp_handle_ack(pData, tp); 421 break; 422 } 423 } 736 } 737 } -
trunk/src/VBox/Devices/Network/slirp/tftp.h
r28800 r41970 31 31 #define TFTP_FILENAME_MAX 512 32 32 33 #if 0 33 34 struct tftp_t 34 35 { … … 51 52 } x; 52 53 }; 54 #else 55 #pragma pack(0) 56 typedef struct TFTPCOREHDR 57 { 58 uint16_t u16TftpOpCode; 59 #if 0 60 union { 61 uint16_t u16BlockNum; 62 uint16_t u16TftpErrorCode; 63 } X; 64 #endif 65 /* Data lays here (might be raw uint8_t* or header of payload ) */ 66 } TFTPCOREHDR, *PTFTPCOREHDR; 67 68 typedef struct TFTPIPHDR 69 { 70 struct ip IPv4Hdr; 71 struct udphdr UdpHdr; 72 uint16_t u16TftpOpType; 73 TFTPCOREHDR Core; 74 /* Data lays here */ 75 } TFTPIPHDR, *PTFTPIPHDR; 76 #pragma pack() 77 78 typedef const PTFTPIPHDR PCTFTPIPHDR; 79 #endif 53 80 54 81 void tftp_input(PNATState pData, struct mbuf *m);
Note:
See TracChangeset
for help on using the changeset viewer.