1 #include <assert.h> 2 #include <ctype.h> 3 #include <string.h> 4 #ifdef ENABLE_DEBUG_EVENT 5 #include <stdarg.h> 6 #endif 7 8 #include "mtcp.h" 9 #include "mos_api.h" 10 #include "debug.h" 11 #include "config.h" 12 #include "ip_in.h" 13 #include "tcp_out.h" 14 /*----------------------------------------------------------------------------*/ 15 #define MAX(x, y) (((x) > (y)) ? (x) : (y)) 16 #define MIN(x, y) (((x) < (y)) ? (x) : (y)) 17 #define SKIP_SPACES(x) while (*x && isspace((int)*x)) x++; 18 #define SKIP_CHAR(x) while((*x) && !isspace(*x)) x++; 19 20 #define KW_AND "and " 21 #define KW_OR "or " 22 #define KW_NOT "not " 23 #define KW_TCP "tcp" 24 #define KW_NOT_TCP "!tcp" 25 #define KW_NOT_TCP2 "not tcp" 26 #define KW_SRC "src " 27 #define KW_DST "dst " 28 #define KW_HOST "host " 29 #define KW_NET "net " 30 #define KW_MASK "mask " 31 #define KW_PORT "port " 32 #define KW_PORTRANGE "portrange " 33 /*----------------------------------------------------------------------------*/ 34 int 35 IsValidFlowRule(char *cf) 36 { 37 char *word; 38 int skip_word = 0; 39 40 /* '!tcp' or 'not tcp' are also not supported in TCP flow filter */ 41 if (strstr(cf, KW_NOT_TCP) || strstr(cf, KW_NOT_TCP2)) { 42 TRACE_ERROR("'!tcp' or 'not tcp' is not a valid rule for TCP flow monitor.\n"); 43 return FALSE; 44 } 45 46 /* verify that the rule contains flow-related keywords only */ 47 word = cf; 48 SKIP_SPACES(word); 49 50 /* while (browse the rule by words) */ 51 while (*word) { 52 if (skip_word) { 53 skip_word = 0; 54 SKIP_CHAR(word); 55 SKIP_SPACES(word); 56 continue; 57 } 58 /* parse the keyword */ 59 /* case "tcp" "src" "dst" "not' "and" "or" -> move to the next word */ 60 if (!strncmp(word, KW_TCP, sizeof(KW_TCP) - 1) || 61 !strncmp(word, KW_SRC, sizeof(KW_SRC) - 1) || 62 !strncmp(word, KW_DST, sizeof(KW_DST) - 1) || 63 !strncmp(word, KW_NOT, sizeof(KW_NOT) - 1) || 64 !strncmp(word, KW_AND, sizeof(KW_AND) - 1) || 65 !strncmp(word, KW_OR, sizeof(KW_OR) - 1)) { 66 skip_word = 0; 67 } 68 /* case "net" "mask" "port" "portrange" -> skip a word (= param) */ 69 else if (!strncmp(word, KW_HOST, sizeof(KW_HOST) - 1) || 70 !strncmp(word, KW_NET, sizeof(KW_NET) - 1) || 71 !strncmp(word, KW_MASK, sizeof(KW_MASK) - 1) || 72 !strncmp(word, KW_PORT, sizeof(KW_PORT) - 1) || 73 !strncmp(word, KW_PORTRANGE, sizeof(KW_PORTRANGE) - 1)) { 74 skip_word = 1; 75 } 76 /* default (rule has any invalid keyword) -> return error */ 77 else { 78 TRACE_ERROR("Invalid keyword in filter (%s)\n", word); 79 return FALSE; 80 } 81 82 SKIP_CHAR(word); 83 SKIP_SPACES(word); 84 } 85 86 return TRUE; 87 } 88 /*----------------------------------------------------------------------------*/ 89 /* Assign an address range (specified by ft) to monitor via sock */ 90 int 91 mtcp_bind_monitor_filter(mctx_t mctx, int sockid, monitor_filter_t ft) 92 { 93 socket_map_t sock; 94 mtcp_manager_t mtcp; 95 96 mtcp = GetMTCPManager(mctx); 97 if (!mtcp) { 98 errno = EACCES; 99 return -1; 100 } 101 102 /* if filter is not set, do nothing and return */ 103 if (ft == NULL) { 104 TRACE_ERROR("filter not set!\n"); 105 return 0; 106 } 107 108 /* retrieve the socket */ 109 if (sockid < 0 || sockid >= g_config.mos->max_concurrency) { 110 errno = EBADF; 111 TRACE_ERROR("sockid is invalid!\n"); 112 return -1; 113 } 114 sock = &mtcp->msmap[sockid]; 115 116 /* check socket type */ 117 switch (sock->socktype) { 118 case MOS_SOCK_MONITOR_RAW: 119 /* For MONITOR_RAW type, allow any bpf rule */ 120 if (!ft->raw_pkt_filter) { 121 TRACE_ERROR("raw pkt filter is null"); 122 return 0; 123 } 124 if (SET_BPFFILTER(&sock->monitor_listener->raw_pkt_fcode, 125 ft->raw_pkt_filter) < 0) { 126 TRACE_ERROR("Invalid filter expression!\n"); 127 errno = EINVAL; 128 return -1; 129 } 130 break; 131 case MOS_SOCK_MONITOR_STREAM: 132 /* For MONITOR_STREAM_PASSIVE type, restrict to flow-level keywords */ 133 if (ft->stream_syn_filter) { 134 if (!IsValidFlowRule(ft->stream_syn_filter)) { 135 errno = EINVAL; 136 return -1; 137 } 138 if (SET_BPFFILTER(&sock->monitor_listener->stream_syn_fcode, 139 ft->stream_syn_filter) < 0) { 140 TRACE_ERROR("Invalid filter expression!\n"); 141 errno = EINVAL; 142 return -1; 143 } 144 } 145 if (ft->stream_orphan_filter) { 146 if (!IsValidFlowRule(ft->stream_orphan_filter)) { 147 errno = EINVAL; 148 return -1; 149 } 150 if (SET_BPFFILTER(&sock->monitor_listener->stream_orphan_fcode, 151 ft->stream_orphan_filter) < 0) { 152 TRACE_ERROR("Invalid filter expression!\n"); 153 errno = EINVAL; 154 return -1; 155 } 156 } 157 break; 158 default: 159 /* return error for other socket types */ 160 errno = ENOPROTOOPT; 161 TRACE_ERROR("Invalid sock type!\n"); 162 return -1; 163 } 164 165 return 0; 166 } 167 /*----------------------------------------------------------------------------*/ 168 void 169 mtcp_app_join(mctx_t mctx) 170 { 171 mtcp_manager_t mtcp = GetMTCPManager(mctx); 172 if (!mtcp) return; 173 174 RunPassiveLoop(mtcp); 175 return; 176 } 177 /*----------------------------------------------------------------------------*/ 178 /* Callback only functions */ 179 /*----------------------------------------------------------------------------*/ 180 void 181 mtcp_set_uctx(mctx_t mctx, int msock, void *uctx) 182 { 183 mtcp_manager_t mtcp; 184 185 mtcp = GetMTCPManager(mctx); 186 if (!mtcp) { 187 return; 188 } 189 190 /* check if the calling thread is in MOS context */ 191 if (mtcp->ctx->thread != pthread_self()) 192 return; 193 194 if (msock < 0 || msock >= g_config.mos->max_concurrency) { 195 TRACE_API("Socket id %d out of range.\n", msock); 196 errno = EBADF; 197 return; 198 } 199 200 socket_map_t socket = &mtcp->msmap[msock]; 201 if (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE) 202 socket->monitor_stream->uctx = uctx; 203 else if (socket->socktype == MOS_SOCK_MONITOR_STREAM || 204 socket->socktype == MOS_SOCK_MONITOR_RAW) 205 socket->monitor_listener->uctx = uctx; 206 } 207 /*----------------------------------------------------------------------------*/ 208 void * 209 mtcp_get_uctx(mctx_t mctx, int msock) 210 { 211 mtcp_manager_t mtcp; 212 213 mtcp = GetMTCPManager(mctx); 214 if (!mtcp) { 215 errno = EACCES; 216 return NULL; 217 } 218 219 /* check if the calling thread is in MOS context */ 220 if (mtcp->ctx->thread != pthread_self()) { 221 errno = EPERM; 222 return NULL; 223 } 224 225 if (msock < 0 || msock >= g_config.mos->max_concurrency) { 226 TRACE_API("Socket id %d out of range.\n", msock); 227 errno = EBADF; 228 return NULL; 229 } 230 231 socket_map_t socket = &mtcp->msmap[msock]; 232 if (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE) 233 return socket->monitor_stream->uctx; 234 else if (socket->socktype == MOS_SOCK_MONITOR_STREAM || 235 socket->socktype == MOS_SOCK_MONITOR_RAW) 236 return socket->monitor_listener->uctx; 237 else 238 return NULL; 239 } 240 /*----------------------------------------------------------------------------*/ 241 ssize_t 242 mtcp_peek(mctx_t mctx, int msock, int side, char *buf, size_t len) 243 { 244 int copylen, rc; 245 struct tcp_stream *cur_stream; 246 mtcp_manager_t mtcp; 247 socket_map_t sock; 248 249 copylen = rc = 0; 250 mtcp = GetMTCPManager(mctx); 251 if (!mtcp) { 252 errno = EACCES; 253 return -1; 254 } 255 256 /* check if the calling thread is in MOS context */ 257 if (mtcp->ctx->thread != pthread_self()) { 258 errno = EPERM; 259 return -1; 260 } 261 262 /* check if the socket is monitor stream */ 263 sock = &mtcp->msmap[msock]; 264 if (sock->socktype != MOS_SOCK_MONITOR_STREAM_ACTIVE) { 265 TRACE_DBG("Invalid socket type!\n"); 266 errno = EBADF; 267 return -1; 268 } 269 270 if (side != MOS_SIDE_CLI && side != MOS_SIDE_SVR) { 271 TRACE_ERROR("Invalid side requested!\n"); 272 exit(EXIT_FAILURE); 273 return -1; 274 } 275 276 struct tcp_stream *mstrm = sock->monitor_stream->stream; 277 cur_stream = (side == mstrm->side) ? mstrm : mstrm->pair_stream; 278 279 if (!cur_stream || !cur_stream->buffer_mgmt) { 280 TRACE_DBG("Stream is NULL!! or buffer management is disabled\n"); 281 errno = EINVAL; 282 return -1; 283 } 284 285 /* Check if the read was not just due to syn-ack recv */ 286 if (cur_stream->rcvvar != NULL && 287 cur_stream->rcvvar->rcvbuf != NULL) { 288 tcprb_t *rcvbuf = cur_stream->rcvvar->rcvbuf; 289 loff_t *poff = &sock->monitor_stream->peek_offset[cur_stream->side]; 290 291 rc = tcprb_ppeek(rcvbuf, (uint8_t *)buf, len, *poff); 292 if (rc < 0) { 293 errno = ENODATA; 294 return -1; 295 } 296 297 *poff += rc; 298 UNUSED(copylen); 299 300 return rc; 301 } else { 302 TRACE_DBG("Stream hasn't yet been initialized!\n"); 303 rc = 0; 304 } 305 306 return rc; 307 } 308 /*----------------------------------------------------------------------------*/ 309 /** 310 * Copies from the frags.. returns no. of bytes copied to buf 311 */ 312 static inline int 313 ExtractPayloadFromFrags(struct tcp_ring_buffer *rcvbuf, char *buf, 314 size_t count, off_t seq_num) 315 { 316 int cpbytesleft; 317 struct fragment_ctx *it; 318 319 it = rcvbuf->fctx; 320 cpbytesleft = count; 321 /* go through each frag */ 322 while (it) { 323 /* first check whether sequent number matches */ 324 if (TCP_SEQ_BETWEEN(seq_num, it->seq, it->seq + it->len)) { 325 /* copy buf starting from seq# seq_num */ 326 /* copy the MIN of seq-range and bytes to be copied */ 327 memcpy(buf + count - cpbytesleft, 328 rcvbuf->head + seq_num - rcvbuf->head_seq, 329 MIN(it->len - (seq_num - it->seq), cpbytesleft)); 330 /* update target seq num */ 331 seq_num += it->len - (seq_num - it->seq); 332 /* update cpbytes left */ 333 cpbytesleft -= it->len - (seq_num - it->seq); 334 if (cpbytesleft == 0) 335 break; 336 } 337 it = it->next; 338 } 339 340 count -= cpbytesleft; 341 342 /* return number of bytes copied */ 343 return count; 344 } 345 /*----------------------------------------------------------------------------*/ 346 /* Please see in-code comments for description */ 347 ssize_t 348 mtcp_ppeek(mctx_t mctx, int msock, int side, 349 char *buf, size_t count, uint64_t off) 350 { 351 mtcp_manager_t mtcp; 352 struct tcp_stream *cur_stream; 353 int rc; 354 socket_map_t sock; 355 356 mtcp = GetMTCPManager(mctx); 357 if (!mtcp) { 358 errno = EACCES; 359 goto ppeek_error; 360 } 361 362 /* check if the calling thread is in MOS context */ 363 if (mtcp->ctx->thread != pthread_self()) { 364 errno = EPERM; 365 goto ppeek_error; 366 } 367 368 /* check if the socket is monitor stream */ 369 sock = &mtcp->msmap[msock]; 370 if (sock->socktype != MOS_SOCK_MONITOR_STREAM_ACTIVE) { 371 TRACE_DBG("Invalid socket type!\n"); 372 errno = ESOCKTNOSUPPORT; 373 goto ppeek_error; 374 } 375 376 if (side != MOS_SIDE_CLI && side != MOS_SIDE_SVR) { 377 TRACE_ERROR("Invalid side requested!\n"); 378 exit(EXIT_FAILURE); 379 return -1; 380 } 381 382 struct tcp_stream *mstrm = sock->monitor_stream->stream; 383 cur_stream = (side == mstrm->side) ? mstrm : mstrm->pair_stream; 384 385 if (!cur_stream || !cur_stream->buffer_mgmt) { 386 TRACE_DBG("Stream is either NULL or ring buffer is not managed!!\n"); 387 errno = EACCES; 388 goto ppeek_error; 389 } 390 391 rc = 0; 392 /* Check if the read was not just due to syn-ack recv */ 393 if (cur_stream->rcvvar != NULL && 394 cur_stream->rcvvar->rcvbuf != NULL) { 395 tcprb_t *rcvbuf = cur_stream->rcvvar->rcvbuf; 396 return tcprb_ppeek(rcvbuf, (uint8_t *)buf, count, off); 397 } else { 398 errno = EPERM; 399 goto ppeek_error; 400 } 401 402 return rc; 403 404 ppeek_error: 405 return -1; 406 } 407 /*----------------------------------------------------------------------------*/ 408 #ifdef MTCP_CB_GETCURPKT_CREATE_COPY 409 static __thread unsigned char local_frame[ETHERNET_FRAME_LEN]; 410 inline struct pkt_info * 411 ClonePacketCtx(struct pkt_info *to, unsigned char *frame, struct pkt_info *from) 412 { 413 /* memcpy the entire ethernet frame */ 414 assert(from); 415 assert(from->eth_len > 0); 416 assert(from->eth_len <= ETHERNET_FRAME_LEN); 417 memcpy(frame, from->ethh, from->eth_len); 418 419 /* only memcpy till the last field before ethh */ 420 /* memcpy(to, from, PCTX_COPY_LEN); */ 421 memcpy(to, from, PKT_INFO_LEN); 422 /* set iph */ 423 to->ethh = (struct ethhdr *)frame; 424 /* set iph */ 425 to->iph = from->iph ? 426 (struct iphdr *)((uint8_t *)(frame + ETHERNET_HEADER_LEN)) : NULL; 427 /* set tcph */ 428 to->tcph = from->tcph ? 429 (struct tcphdr *)(((uint8_t *)(to->iph)) + (to->iph->ihl<<2)) : NULL; 430 /* set payload */ 431 to->payload = from->tcph ? 432 ((uint8_t *)(to->tcph) + (to->tcph->doff<<2)) : NULL; 433 return to; 434 } 435 /*----------------------------------------------------------------------------*/ 436 int 437 mtcp_getlastpkt(mctx_t mctx, int sock, int side, struct pkt_info *pkt) 438 { 439 mtcp_manager_t mtcp; 440 socket_map_t socket; 441 struct pkt_ctx *cur_pkt_ctx; 442 443 mtcp = GetMTCPManager(mctx); 444 if (!mtcp) { 445 errno = EACCES; 446 return -1; 447 } 448 449 /* check if the calling thread is in MOS context */ 450 if (mtcp->ctx->thread != pthread_self()) { 451 errno = EPERM; 452 return -1; 453 } 454 455 /* check if the socket is monitor stream */ 456 socket = &mtcp->msmap[sock]; 457 #ifndef RECORDPKT_PER_STREAM 458 switch (socket->socktype) { 459 case MOS_SOCK_MONITOR_STREAM_ACTIVE: 460 case MOS_SOCK_MONITOR_RAW: 461 case MOS_SOCK_MONITOR_STREAM: 462 if (mtcp->pctx == NULL) { 463 errno = EACCES; 464 return -1; 465 } 466 cur_pkt_ctx = mtcp->pctx; 467 break; 468 default: 469 TRACE_DBG("Invalid socket type!\n"); 470 errno = EBADF; 471 return -1; 472 } 473 #else /* RECORDPKT_PER_STREAM */ 474 struct tcp_stream *cur_stream; 475 if (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE) { 476 if (side != MOS_SIDE_CLI && side != MOS_SIDE_SVR) { 477 TRACE_ERROR("Invalid side requested!\n"); 478 exit(EXIT_FAILURE); 479 return -1; 480 } 481 482 struct tcp_stream *mstrm = socket->monitor_stream->stream; 483 cur_stream = (side == mstrm->side) ? mstrm : mstrm->pair_stream; 484 485 cur_pkt_ctx = &cur_stream->last_pctx; 486 if (!cur_pkt_ctx->p.ethh) { 487 errno = ENODATA; 488 return -1; 489 } 490 } else if (socket->socktype == MOS_SOCK_MONITOR_RAW) { 491 cur_pkt_ctx = mtcp->pctx; 492 } else if (socket->socktype == MOS_SOCK_MONITOR_STREAM) { 493 /* 494 * if it is a monitor socket, then this means that 495 * this is a request for an orphan tcp packet 496 */ 497 cur_pkt_ctx = mtcp->pctx; 498 } else { 499 TRACE_DBG("Invalid socket type!\n"); 500 errno = EBADF; 501 return -1; 502 } 503 #endif /* !RECORDPKT_PER_STREAM */ 504 ClonePacketCtx(pkt, local_frame, &(cur_pkt_ctx->p)); 505 return 0; 506 } 507 #else 508 /*----------------------------------------------------------------------------*/ 509 int 510 mtcp_getlastpkt(mctx_t mctx, int sock, int side, struct pkt_ctx **pctx) 511 { 512 mtcp_manager_t mtcp; 513 514 mtcp = GetMTCPManager(mctx); 515 if (!mtcp) { 516 errno = EACCES; 517 return -1; 518 } 519 520 /* check if the calling thread is in MOS context */ 521 if (mtcp->ctx->thread != pthread_self()) { 522 errno = EPERM; 523 return -1; 524 } 525 /* just pass direct pointer */ 526 *pctx = mtcp->pctx; 527 528 return 0; 529 } 530 #endif 531 /*----------------------------------------------------------------------------*/ 532 int 533 mtcp_sendpkt(mctx_t mctx, int sock, const struct pkt_info *pkt) 534 { 535 mtcp_manager_t mtcp; 536 socket_map_t socket; 537 538 mtcp = GetMTCPManager(mctx); 539 if (!mtcp || !pkt) { 540 errno = EACCES; 541 return -1; 542 } 543 544 /* check if the calling thread is in MOS context */ 545 if (mtcp->ctx->thread != pthread_self()) { 546 errno = EPERM; 547 return -1; 548 } 549 550 /* check if the socket is monitor stream */ 551 socket = &mtcp->msmap[sock]; 552 553 if (!(pkt->iph) || !(pkt->tcph)) { 554 errno = ENODATA; 555 TRACE_INFO("mtcp_sendpkt() only supports TCP packet for now.\n"); 556 return -1; 557 } 558 559 if (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE) { 560 SendTCPPacketStandalone(mtcp, 561 pkt->iph->saddr, pkt->tcph->source, 562 pkt->iph->daddr, pkt->tcph->dest, 563 htonl(pkt->tcph->seq), htonl(pkt->tcph->ack_seq), 564 ntohs(pkt->tcph->window), TCP_FLAG_ACK, 565 pkt->payload, pkt->payloadlen, 566 socket->monitor_stream->stream->rcvvar->ts_recent, 567 socket->monitor_stream->stream->rcvvar->ts_lastack_rcvd, 568 pkt->iph->id, pkt->in_ifidx); 569 570 571 } 572 573 return 0; 574 } 575 /*----------------------------------------------------------------------------*/ 576 /** Disable events from the monitor stream socket 577 * @param [in] mtcp: mtcp_manager 578 * @param [in] sock: socket 579 * 580 * returns 0 on success, -1 on failure 581 * 582 * This is used for flow management based monitoring sockets 583 */ 584 int 585 RemoveMonitorEvents(mtcp_manager_t mtcp, socket_map_t socket, int side) 586 { 587 struct mon_stream *mstream; 588 struct mon_listener *mlistener; 589 590 if (mtcp == NULL) { 591 TRACE_DBG("mtcp is not defined!!!\n"); 592 errno = EACCES; 593 return -1; 594 } 595 596 switch (socket->socktype) { 597 case MOS_SOCK_MONITOR_STREAM_ACTIVE: 598 mstream = socket->monitor_stream; 599 if (mstream == NULL) { 600 TRACE_ERROR("Mon Stream does not exist!\n"); 601 /* exit(-1); */ 602 errno = ENODATA; 603 return -1; 604 } 605 606 if (side == MOS_SIDE_SVR) mstream->server_mon = 0; 607 else if (side == MOS_SIDE_CLI) mstream->client_mon = 0; 608 609 if (mstream->server_mon == 0 && mstream->client_mon == 0) { 610 #ifdef NEWEV 611 /* 612 * if stree_dontcare is NULL, then we know that all 613 * events have already been disabled 614 */ 615 if (mstream->stree_pre_rcv != NULL) { 616 stree_dec_ref(mtcp->ev_store, mstream->stree_dontcare); 617 stree_dec_ref(mtcp->ev_store, mstream->stree_pre_rcv); 618 stree_dec_ref(mtcp->ev_store, mstream->stree_post_snd); 619 620 mstream->stree_dontcare = NULL; 621 mstream->stree_pre_rcv = NULL; 622 mstream->stree_post_snd = NULL; 623 } 624 #else 625 /* no error checking over here.. 626 * but its okay.. this code is 627 * deprecated 628 */ 629 CleanupEvP(&mstream->dontcare_evp); 630 CleanupEvP(&mstream->pre_tcp_evp); 631 CleanupEvP(&mstream->post_tcp_evp); 632 #endif 633 } 634 break; 635 case MOS_SOCK_MONITOR_STREAM: 636 mlistener = socket->monitor_listener; 637 if (mlistener == NULL) { 638 TRACE_ERROR("Mon listener does not exist!\n"); 639 errno = ENODATA; 640 return -1; 641 } 642 643 if (side == MOS_SIDE_SVR) mlistener->server_mon = 0; 644 else if (side == MOS_SIDE_CLI) mlistener->client_mon = 0; 645 646 if (mlistener->server_mon == 0 && mlistener->client_mon == 0) { 647 #ifdef NEWEV 648 /* 649 * if stree_dontcare is NULL, then we know that all 650 * events have already been disabled 651 */ 652 if (mlistener->stree_pre_rcv != NULL) { 653 stree_dec_ref(mtcp->ev_store, mlistener->stree_dontcare); 654 stree_dec_ref(mtcp->ev_store, mlistener->stree_pre_rcv); 655 stree_dec_ref(mtcp->ev_store, mlistener->stree_post_snd); 656 657 mlistener->stree_dontcare = NULL; 658 mlistener->stree_pre_rcv = NULL; 659 mlistener->stree_post_snd = NULL; 660 } 661 #else 662 /* no error checking over here.. 663 * but its okay.. this code is 664 * deprecated 665 */ 666 CleanupEvB(mtcp, &mlistener->dontcare_evb); 667 CleanupEvB(mtcp, &mlistener->pre_tcp_evb); 668 CleanupEvB(mtcp, &mlistener->post_tcp_evb); 669 #endif 670 } 671 break; 672 default: 673 TRACE_ERROR("Invalid socket type!\n"); 674 } 675 676 return 0; 677 } 678 /*----------------------------------------------------------------------------*/ 679 /** 680 * Disable monitoring based on side variable. 681 */ 682 int 683 mtcp_cb_stop(mctx_t mctx, int sock, int side) 684 { 685 mtcp_manager_t mtcp; 686 socket_map_t socket; 687 struct tcp_stream *stream; 688 struct socket_map *walk; 689 uint8_t mgmt; 690 691 mtcp = GetMTCPManager(mctx); 692 if (!mtcp) { 693 errno = EACCES; 694 return -1; 695 } 696 697 socket = &mtcp->msmap[sock]; 698 699 /* works for both monitor listener and stream sockets */ 700 RemoveMonitorEvents(mtcp, socket, side); 701 702 /* passive monitoring socket is not connected to any stream */ 703 if (socket->socktype == MOS_SOCK_MONITOR_STREAM) 704 return 0; 705 706 if (side == MOS_SIDE_CLI) { 707 /* see if the associated stream requires monitoring any more */ 708 stream = (socket->monitor_stream->stream->side == MOS_SIDE_CLI) ? 709 socket->monitor_stream->stream : 710 socket->monitor_stream->stream->pair_stream; 711 712 mgmt = 0; 713 SOCKQ_FOREACH_START(walk, &stream->msocks) { 714 if (walk->monitor_stream->client_mon == 1) { 715 mgmt = 1; 716 break; 717 } 718 } SOCKQ_FOREACH_END; 719 /* if all streams have mgmt off, then tag the stream for destruction */ 720 if (mgmt == 0) { 721 stream = (socket->monitor_stream->stream->side == MOS_SIDE_CLI) ? 722 socket->monitor_stream->stream : 723 socket->monitor_stream->stream->pair_stream; 724 stream->status_mgmt = 0; 725 } 726 } 727 728 if (side == MOS_SIDE_SVR) { 729 /* see if the associated stream requires monitoring any more */ 730 stream = (socket->monitor_stream->stream->side == MOS_SIDE_SVR) ? 731 socket->monitor_stream->stream : 732 socket->monitor_stream->stream->pair_stream; 733 mgmt = 0; 734 SOCKQ_FOREACH_START(walk, &stream->msocks) { 735 if (walk->monitor_stream->server_mon == 1) { 736 mgmt = 1; 737 break; 738 } 739 } SOCKQ_FOREACH_END; 740 /* if all streams have mgmt off, then tag the stream for destruction */ 741 if (mgmt == 0) { 742 stream = (socket->monitor_stream->stream->side == MOS_SIDE_SVR) ? 743 socket->monitor_stream->stream : 744 socket->monitor_stream->stream->pair_stream; 745 stream->status_mgmt = 0; 746 } 747 } 748 749 return 0; 750 } 751 /*----------------------------------------------------------------------------*/ 752 /** 753 * send a RST packet to the TCP stream (uni-directional) 754 */ 755 static inline void 756 SendRSTPacketStandalone(mtcp_manager_t mtcp, struct tcp_stream *stream) { 757 SendTCPPacketStandalone(mtcp, 758 stream->saddr, stream->sport, stream->daddr, stream->dport, 759 stream->snd_nxt, stream->rcv_nxt, 0, TCP_FLAG_RST | TCP_FLAG_ACK, 760 NULL, 0, mtcp->cur_ts, 0, 0, -1); 761 } 762 /*----------------------------------------------------------------------------*/ 763 /** 764 * Reset the connection (send RST packets to both sides) 765 */ 766 int 767 mtcp_reset_conn(mctx_t mctx, int sock) 768 { 769 mtcp_manager_t mtcp; 770 socket_map_t socket; 771 772 mtcp = GetMTCPManager(mctx); 773 if (!mtcp) { 774 errno = EACCES; 775 return -1; 776 } 777 778 socket = &mtcp->msmap[sock]; 779 780 /* passive monitoring socket is not connected to any stream */ 781 if (socket->socktype == MOS_SOCK_MONITOR_STREAM) { 782 errno = EINVAL; 783 return -1; 784 } 785 786 /* send RST packets to the both sides */ 787 SendRSTPacketStandalone(mtcp, socket->monitor_stream->stream); 788 SendRSTPacketStandalone(mtcp, socket->monitor_stream->stream->pair_stream); 789 790 return 0; 791 } 792 /*----------------------------------------------------------------------------*/ 793 uint32_t 794 mtcp_cb_get_ts(mctx_t mctx) 795 { 796 mtcp_manager_t mtcp; 797 798 mtcp = GetMTCPManager(mctx); 799 if (!mtcp) { 800 TRACE_DBG("Can't access MTCP manager!\n"); 801 errno = EACCES; 802 return 0; 803 } 804 805 /* check if the calling thread is in MOS context */ 806 if (mtcp->ctx->thread != pthread_self()) { 807 errno = EPERM; 808 return 0; 809 } 810 811 return TS_TO_USEC(mtcp->cur_ts); 812 } 813 /*----------------------------------------------------------------------------*/ 814 /* Macros related to getpeername */ 815 #define TILL_SVRADDR offsetof(struct sockaddr_in, sin_zero) 816 #define TILL_SVRPORT offsetof(struct sockaddr_in, sin_addr) 817 #define TILL_SVRFAMILY offsetof(struct sockaddr_in, sin_port) 818 #define TILL_CLIADDR sizeof(struct sockaddr) + TILL_SVRADDR 819 #define TILL_CLIPORT sizeof(struct sockaddr) + TILL_SVRPORT 820 #define TILL_CLIFAMILY sizeof(struct sockaddr) + TILL_SVRFAMILY 821 822 int 823 mtcp_getpeername(mctx_t mctx, int sockfd, struct sockaddr *saddr, 824 socklen_t *addrlen, int side) 825 { 826 mtcp_manager_t mtcp; 827 socket_map_t socket; 828 struct tcp_stream *stream; 829 struct sockaddr_in *sin; 830 int rc; 831 832 mtcp = GetMTCPManager(mctx); 833 if (!mtcp) { 834 TRACE_DBG("Can't access MTCP manager!\n"); 835 errno = EACCES; 836 return -1; 837 } 838 839 /* check if sockfd is within limits */ 840 if (sockfd < 0 || sockfd >= g_config.mos->max_concurrency) { 841 TRACE_API("Socket id %d out of range.\n", sockfd); 842 errno = EBADF; 843 return -1; 844 } 845 846 /* check if the calling thread is in MOS context */ 847 if (mtcp->ctx->thread != pthread_self()) { 848 errno = EPERM; 849 return -1; 850 } 851 852 socket = &mtcp->msmap[sockfd]; 853 sin = (struct sockaddr_in *)saddr; 854 rc = 0; 855 856 /* retrieve both streams */ 857 stream = socket->monitor_stream->stream; 858 859 if (side != stream->side) 860 stream = stream->pair_stream; 861 862 if (stream == NULL) { 863 errno = ENOTCONN; 864 return -1; 865 } 866 867 /* reset to 2 * sizeof(struct sockaddr) if addrlen is too big */ 868 if (*addrlen > 2 * sizeof(struct sockaddr)) 869 *addrlen = 2 * sizeof(struct sockaddr); 870 871 /* according per manpage, address can be truncated */ 872 switch (*addrlen) { 873 case (2 * sizeof(struct sockaddr)): 874 case TILL_CLIADDR: 875 sin[1].sin_addr.s_addr = stream->side == MOS_SIDE_SVR ? 876 stream->daddr : stream->saddr; 877 case TILL_CLIPORT: 878 sin[1].sin_port = stream->side == MOS_SIDE_SVR ? 879 stream->dport : stream->sport; 880 case TILL_CLIFAMILY: 881 sin[1].sin_family = AF_INET; 882 case (sizeof(struct sockaddr)): 883 case TILL_SVRADDR: 884 sin->sin_addr.s_addr = stream->side == MOS_SIDE_SVR ? 885 stream->saddr : stream->daddr; 886 case TILL_SVRPORT: 887 sin->sin_port = stream->side == MOS_SIDE_SVR ? 888 stream->sport : stream->dport; 889 case TILL_SVRFAMILY: 890 sin->sin_family = AF_INET; 891 break; 892 default: 893 rc = -1; 894 *addrlen = 0xFFFF; 895 errno = EINVAL; 896 } 897 898 return rc; 899 } 900 /*----------------------------------------------------------------------------*/ 901 int 902 mtcp_setlastpkt(mctx_t mctx, int sock, int side, off_t offset, 903 byte *data, uint16_t datalen, int option) 904 { 905 mtcp_manager_t mtcp; 906 struct pkt_ctx *cur_pkt_ctx; 907 struct ethhdr *ethh; 908 struct iphdr *iph; 909 struct tcphdr *tcph; 910 unsigned char *payload; 911 912 #if 0 913 socket_map_t socket; 914 struct tcp_stream *cur_stream; 915 #endif 916 917 /* checking if mtcp is valid */ 918 mtcp = GetMTCPManager(mctx); 919 if (!mtcp) { 920 errno = EACCES; 921 TRACE_ERROR("Invalid mtcp!\n"); 922 return -1; 923 } 924 925 /* check if the calling thread is in MOS context */ 926 if (mtcp->ctx->thread != pthread_self()) { 927 errno = EPERM; 928 TRACE_ERROR("Invalid thread id!\n"); 929 return -1; 930 } 931 932 #if 0 933 /* check if the socket is monitor stream */ 934 socket = &mtcp->msmap[sock]; 935 if (socket->socktype == MOS_SOCK_MONITOR_STREAM_ACTIVE) { 936 if (side != MOS_SIDE_CLI && side != MOS_SIDE_SVR) { 937 TRACE_ERROR("Invalid side requested!\n"); 938 exit(EXIT_FAILURE); 939 return -1; 940 } 941 942 struct tcp_stream *mstrm = socket->monitor_stream->stream; 943 cur_stream = (side == mstrm->side) ? mstrm : mstrm->pair_stream; 944 945 if (!cur_stream->allow_pkt_modification) 946 return -1; 947 } else if (socket->socktype != MOS_SOCK_MONITOR_RAW) { 948 TRACE_ERROR("Invalid socket type!\n"); 949 exit(EXIT_FAILURE); 950 return -1; 951 } 952 #endif 953 954 /* see if cur_pkt_ctx is valid */ 955 cur_pkt_ctx = mtcp->pctx; 956 if (cur_pkt_ctx == NULL) { 957 TRACE_ERROR("pctx is NULL!\n"); 958 errno = ENODATA; 959 return -1; 960 } 961 962 /* check if offset is valid */ 963 if (offset < 0) { 964 TRACE_ERROR("Invalid offset position!\n"); 965 errno = EINVAL; 966 return -1; 967 } 968 969 if (__builtin_popcount(option & (MOS_DROP | MOS_CHOMP | 970 MOS_INSERT | MOS_OVERWRITE)) != 1) { 971 TRACE_ERROR("mtcp_setlastpkt() function only allows one of " 972 "(MOS_DROP | MOS_CHOMP | MOS_INSERT | MOS_OVERWRITE) " 973 "to be set at a time.\n"); 974 errno = EAGAIN; 975 return -1; 976 } 977 978 /* drop pkt has the highest priority */ 979 if (option & MOS_DROP) { 980 mtcp->pctx->forward = 0; 981 return 0; 982 } else if (option & MOS_ETH_HDR) { 983 /* validity test */ 984 if ((ethh=cur_pkt_ctx->p.ethh) == NULL || 985 offset + datalen > sizeof(struct ethhdr)) { 986 TRACE_ERROR("Ethernet setting has gone out of bounds " 987 "(offset: %ld, datalen: %d)\n", 988 offset, datalen); 989 errno = EINVAL; 990 return -1; 991 } 992 if (option & MOS_CHOMP) { 993 TRACE_ERROR("Illegal call. " 994 "Ethernet header can't be chopped down!\n"); 995 errno = EACCES; 996 return -1; 997 } else if (option & MOS_INSERT) { 998 TRACE_ERROR("Illegal call. " 999 "Ethernet header can't be extended!\n"); 1000 errno = EACCES; 1001 return -1; 1002 } else /* if (option & MOS_OVERWRITE) */ { 1003 memcpy((uint8_t *)ethh + offset, data, datalen); 1004 } 1005 /* iph, tcph, and payload do not need to change */ 1006 } else if (option & MOS_IP_HDR) { 1007 /* validity test */ 1008 if (cur_pkt_ctx->p.ethh == NULL || 1009 cur_pkt_ctx->p.ethh->h_proto != ntohs(ETH_P_IP) || 1010 (iph=(struct iphdr *)(cur_pkt_ctx->p.ethh + 1)) == NULL) { 1011 TRACE_ERROR("ethh or iph are out of bounds\n"); 1012 errno = EACCES; 1013 return -1; 1014 } 1015 if (option & MOS_OVERWRITE) { 1016 if (offset + datalen > (iph->ihl<<2)) { 1017 TRACE_ERROR("IP setting has gone out of bounds " 1018 "(offset: %ld, datalen: %d)\n", 1019 offset, datalen); 1020 errno = EINVAL; 1021 return -1; 1022 } 1023 memcpy((uint8_t *)iph + offset, data, datalen); 1024 } 1025 if (option & MOS_CHOMP) { 1026 memmove((uint8_t *)iph + offset, 1027 (uint8_t *)iph + offset + datalen, 1028 cur_pkt_ctx->p.ip_len - offset - datalen); 1029 1030 /* iph does not need to change */ 1031 if (iph->protocol == IPPROTO_TCP) { 1032 cur_pkt_ctx->p.tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2)); 1033 cur_pkt_ctx->p.payload = (uint8_t *)cur_pkt_ctx->p.tcph + 1034 (cur_pkt_ctx->p.tcph->doff<<2); 1035 } else { 1036 /* reset tcph if iph does not have tcp proto */ 1037 cur_pkt_ctx->p.tcph = NULL; 1038 } 1039 /* update iph total length */ 1040 cur_pkt_ctx->p.ip_len = ntohs(iph->tot_len); 1041 /* update eth frame length */ 1042 cur_pkt_ctx->p.eth_len = cur_pkt_ctx->p.ip_len + sizeof(struct ethhdr); 1043 } else if (option & MOS_INSERT) { 1044 memmove((uint8_t *)iph + offset + datalen, 1045 (uint8_t *)iph + offset + 1, 1046 cur_pkt_ctx->p.ip_len - offset); 1047 memcpy((uint8_t *)iph + offset, 1048 data, datalen); 1049 1050 /* iph does not need to change */ 1051 if (iph->protocol == IPPROTO_TCP) { 1052 cur_pkt_ctx->p.tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2)); 1053 cur_pkt_ctx->p.payload = (uint8_t *)cur_pkt_ctx->p.tcph + 1054 (cur_pkt_ctx->p.tcph->doff<<2); 1055 } else { 1056 /* reset tcph if iph does not have tcp proto */ 1057 cur_pkt_ctx->p.tcph = NULL; 1058 } 1059 /* update iph total length */ 1060 cur_pkt_ctx->p.ip_len = ntohs(iph->tot_len); 1061 /* update eth frame length */ 1062 cur_pkt_ctx->p.eth_len = cur_pkt_ctx->p.ip_len + sizeof(struct ethhdr); 1063 } 1064 /* can't update payloadlen because we don't know tcph->doff */ 1065 } else if (option & MOS_TCP_HDR) { 1066 /* validity test */ 1067 iph = (struct iphdr *)(cur_pkt_ctx->p.ethh + 1); 1068 if (iph == NULL || 1069 iph->protocol != IPPROTO_TCP || 1070 (tcph=(struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2))) == NULL) { 1071 TRACE_ERROR("TCP setting has gone out of bounds " 1072 "(offset: %ld, datalen: %d)\n", 1073 offset, datalen); 1074 errno = EINVAL; 1075 return -1; 1076 } 1077 if (option & MOS_OVERWRITE) { 1078 if (offset + datalen > (tcph->doff<<2)) { 1079 TRACE_ERROR("TCP setting has gone out of bounds " 1080 "(offset: %ld, datalen: %d)\n", 1081 offset, datalen); 1082 errno = EINVAL; 1083 return -1; 1084 } 1085 memcpy((uint8_t *)tcph + offset, data, datalen); 1086 /* update tcp seq # */ 1087 cur_pkt_ctx->p.seq = ntohl(tcph->seq); 1088 /* update tcp ack_seq # */ 1089 cur_pkt_ctx->p.ack_seq = ntohl(tcph->ack_seq); 1090 /* update tcp window */ 1091 cur_pkt_ctx->p.window = ntohs(tcph->window); 1092 1093 /* 150422 dhkim TODO: seq and offset are two different form of same 1094 * variable. We also need to update the offset. */ 1095 } 1096 if (option & MOS_CHOMP) { 1097 memmove((uint8_t *)tcph + offset, 1098 (uint8_t *)tcph + offset + datalen, 1099 cur_pkt_ctx->p.payloadlen + (tcph->doff<<2) 1100 - offset - datalen); 1101 /* update payload ptr */ 1102 cur_pkt_ctx->p.payload = (uint8_t *)tcph + (tcph->doff<<2); 1103 } else if (option & MOS_INSERT) { 1104 memmove((uint8_t *)tcph + offset + datalen, 1105 (uint8_t *)tcph + offset + 1, 1106 cur_pkt_ctx->p.payloadlen + (tcph->doff<<2) 1107 - offset); 1108 memcpy((uint8_t *)tcph + offset, data, datalen); 1109 /* update payload ptr */ 1110 cur_pkt_ctx->p.payload = (uint8_t *)tcph + (tcph->doff<<2); 1111 } 1112 } else if (option & MOS_TCP_PAYLOAD) { 1113 iph = (struct iphdr *)(cur_pkt_ctx->p.ethh + 1); 1114 tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2)); 1115 payload = (uint8_t *)tcph + (tcph->doff<<2); 1116 if (option & MOS_OVERWRITE) { 1117 if (offset + datalen > ntohs(iph->tot_len) - 1118 (iph->ihl<<2) - (tcph->doff<<2)) { 1119 TRACE_ERROR("Payload setting has gone out of bounds " 1120 "(offset: %ld, datalen: %d)\n", 1121 offset, datalen); 1122 errno = EINVAL; 1123 return -1; 1124 } 1125 memcpy(payload + offset, data, datalen); 1126 } 1127 if (option & MOS_CHOMP) { 1128 memmove(payload + offset, 1129 payload + offset + datalen, 1130 (cur_pkt_ctx->p.payloadlen - 1131 offset - datalen)); 1132 /* update payload length */ 1133 cur_pkt_ctx->p.payloadlen = cur_pkt_ctx->p.ip_len - 1134 (tcph->doff<<2) - (iph->ihl<<2); 1135 } else if (option & MOS_INSERT) { 1136 memmove(payload + offset + datalen, 1137 payload + offset + 1, 1138 cur_pkt_ctx->p.payloadlen - offset); 1139 memcpy(payload + offset, data, datalen); 1140 cur_pkt_ctx->p.payloadlen = cur_pkt_ctx->p.ip_len - 1141 (tcph->doff<<2) - (iph->ihl<<2); 1142 } 1143 } else { 1144 TRACE_ERROR("Invalid option!\n"); 1145 errno = EINVAL; 1146 return -1; 1147 } 1148 1149 /* update ip checksum */ 1150 if (option & MOS_UPDATE_IP_CHKSUM) { 1151 iph = (struct iphdr *)(cur_pkt_ctx->p.ethh + 1); 1152 iph->check = 0; 1153 iph->check = ip_fast_csum(iph, iph->ihl); 1154 } 1155 1156 /* update tcp checksum */ 1157 if (option & MOS_UPDATE_TCP_CHKSUM) { 1158 iph = (struct iphdr *)(cur_pkt_ctx->p.ethh + 1); 1159 tcph = (struct tcphdr *)((uint8_t *)iph + (iph->ihl<<2)); 1160 tcph->check = 0; 1161 tcph->check = TCPCalcChecksum((uint16_t *)tcph, 1162 ntohs(iph->tot_len) - (iph->ihl<<2), 1163 iph->saddr, iph->daddr); 1164 } 1165 return 0; 1166 } 1167 /*----------------------------------------------------------------------------*/ 1168 #if 0 1169 inline int 1170 mtcp_cb_updatecurpkt(mctx_t mctx, off_t offset, unsigned char *data, 1171 uint16_t datalen, int option) 1172 { 1173 return mtcp_setlastpkt(mctx, sock, side, offset, data, datalen, option); 1174 } 1175 #endif 1176 /*----------------------------------------------------------------------------*/ 1177 /** 1178 * THIS IS A DEPRECETED FUNCTION... 1179 */ 1180 int 1181 mtcp_cb_dropcurpkt(mctx_t mctx) 1182 { 1183 mtcp_manager_t mtcp; 1184 1185 /* checking if mtcp is valid */ 1186 mtcp = GetMTCPManager(mctx); 1187 if (!mtcp) { 1188 TRACE_ERROR("Invalid mtcp!\n"); 1189 errno = EACCES; 1190 return -1; 1191 } 1192 1193 /* check if the calling thread is in MOS context */ 1194 if (mtcp->ctx->thread != pthread_self()) { 1195 TRACE_ERROR("Invalid thread id!\n"); 1196 errno = EPERM; 1197 return -1; 1198 } 1199 1200 /* see if cur_pkt_ctx is valid */ 1201 if (mtcp->pctx == NULL) { 1202 TRACE_ERROR("pctx is NULL!\n"); 1203 errno = ENODATA; 1204 return -1; 1205 } 1206 1207 mtcp->pctx->forward = 0; 1208 1209 return 0; 1210 } 1211 /*----------------------------------------------------------------------------*/ 1212 int 1213 mtcp_set_debug_string(mtcp_manager_t mtcp, const char *fmt, ...) 1214 { 1215 #ifdef ENABLE_DEBUG_EVENT 1216 va_list args; 1217 int i; 1218 1219 assert(mtcp); 1220 1221 if (fmt == NULL) { 1222 mtcp->dbg_buf[0] = '\0'; 1223 return 0; 1224 } 1225 1226 va_start(args, fmt); 1227 i = vsnprintf(mtcp->dbg_buf, DBG_BUF_LEN - 1, fmt, args); 1228 va_end(args); 1229 1230 return i; 1231 #else 1232 return -1; 1233 #endif /* ENABLE_DEBUG_EVENT */ 1234 } 1235 /*----------------------------------------------------------------------------*/ 1236 int 1237 mtcp_get_debug_string(mctx_t mctx, char *buf, int len) 1238 { 1239 #ifdef ENABLE_DEBUG_EVENT 1240 mtcp_manager_t mtcp; 1241 int copylen; 1242 1243 if (len < 0) 1244 return -1; 1245 else if (len == 0) 1246 return 0; 1247 1248 if (!(mtcp = GetMTCPManager(mctx))) 1249 return -1; 1250 1251 copylen = MIN(strlen(mtcp->dbg_buf), len); 1252 strncpy(buf, mtcp->dbg_buf, copylen); 1253 1254 return copylen; 1255 #else 1256 return -1; 1257 #endif /* ENABLE_DEBUG_EVENT */ 1258 } 1259 /*----------------------------------------------------------------------------*/ 1260