int __bro_openssl_read(BroConn *bc, uchar *buf, uint buf_size) { int n; D_ENTER; /* It's important here to use <= for comparison, since, as the * invaluable O'Reilly OpenSSL book reports, "for each of the four * reading and writing functions, a 0 or -1 return value may or may * not necessarily indicate that an error has occurred." This may or * may not necessarily be indicative of the incredible PITA that * OpenSSL is. --cpk */ if ( (n = BIO_read(bc->bio, buf, buf_size)) <= 0) { if (BIO_should_retry(bc->bio)) D_RETURN_(0); __bro_openssl_shutdown(bc); D(("Connection closed, BIO_read() returned %i.\n", n)); print_errors(); D_RETURN_(-1); } D_RETURN_(n); }
void __bro_io_loop(BroConn *bc) { D_ENTER; for ( ; ; ) { D(("I/O loop iteration\n")); switch (bc->state->io_msg) { case BRO_IOMSG_STOP: D(("I/O process %u exiting by request.\n", getpid())); __bro_openssl_shutdown(bc); exit(0); case BRO_IOMSG_WRITE: if (bc->state->tx_dead) break; if (! io_msg_empty_tx(bc)) { D(("I/O handler %u encountered write error.\n", getpid())); __bro_openssl_shutdown(bc); } break; case BRO_IOMSG_READ: if (bc->state->rx_dead) break; if (io_msg_fill_rx(bc) < 0) { D(("I/O handler %u encountered read error.\n", getpid())); __bro_openssl_shutdown(bc); } break; } bc->state->io_msg = BRO_IOMSG_NONE; } }
int __bro_io_process_input(BroConn *bc) { uint32 buf_off, chunk_size; BroMsgHeader msg_hdr; int result = FALSE; D_ENTER; /* Read all available data into receive buffer. Our socket is * nonblocking so if nothing's available we'll be back right * away. If nothing was read, the subsequent for loop will exit * right away, so the io_msg_fill_rx() return code need not be * checked here. */ io_msg_fill_rx(bc); /* Try to process as much in the input buffer as we can */ for ( ; ; ) { D(("----- Attempting to extract a message\n")); /* Get the current offset of the buffer pointer to make * sure we can reset to it if things go wrong. */ buf_off = __bro_buf_ptr_tell(bc->rx_buf); /* Now check the buffer contents and see if there's enough * for us to analyze it. Start with a uint32 for the size * of the first chunk, and then the chunk itself. */ if (! io_read_chunk_size(bc, &chunk_size)) goto reset_return; if (chunk_size != sizeof(BroMsgHeader)) { D(("Received chunk should be %i bytes, but is %i\n", sizeof(BroMsgHeader), chunk_size)); io_skip_chunk(bc->rx_buf, buf_off, chunk_size); result = TRUE; continue; } if (! io_read_msg_hdr(bc, &msg_hdr)) goto reset_return; switch (msg_hdr.hdr_type) { case BRO_MSG_REQUEST: { char *tmp = NULL, *tmp2 = NULL; D(("Received MSQ_REQUEST\n")); /* We need to read another chunk, whose data will contain * a sequence of 0-terminated strings, each one being the * name of an event that the peering Bro is interested in. */ if (! io_read_chunk_size(bc, &chunk_size)) goto reset_return; if (! (tmp = (char *) malloc(chunk_size * sizeof(char)))) goto reset_return; if (! __bro_buf_read_data(bc->rx_buf, tmp, chunk_size)) { free(tmp); goto reset_return; } for (tmp2 = tmp; tmp2 < tmp + chunk_size; tmp2 = tmp2 + strlen(tmp2) + 1) { char *key; if (__bro_ht_get(bc->ev_mask, tmp2)) continue; key = strdup(tmp2); __bro_ht_add(bc->ev_mask, key, key); D(("Will report event '%s'\n", tmp2)); } D(("Now reporting %i event(s).\n", __bro_ht_get_size(bc->ev_mask))); free(tmp); } break; case BRO_MSG_VERSION: { uchar *data; uint32 proto_version; uint32 cache_size; uint32 data_version; uint32 runtime; /* unused */ D(("Received MSG_VERSION\n")); /* We need to read another chunk for the raw data. */ if (! io_read_chunk_size(bc, &chunk_size)) goto reset_return; if (! (data = malloc(sizeof(uchar) * chunk_size))) goto reset_return; if (! __bro_buf_read_data(bc->rx_buf, data, chunk_size)) { free(data); goto reset_return; } proto_version = ntohl(((uint32 *) data)[0]); cache_size = ntohl(((uint32 *) data)[1]); data_version = ntohl(((uint32 *) data)[2]); runtime = ntohl(((uint32 *) data)[3]); /* If there are more bytes than required for the 4 uint32s * used above, it means that the peer has sent a connection class * identifier. Extract and register in the handle. */ if (chunk_size > 4 * sizeof(uint32)) { if (bc->peer_class) free(bc->peer_class); bc->peer_class = strdup((char *) (data + 4 * sizeof(uint32))); } if (proto_version != BRO_PROTOCOL_VERSION) { D(("EEEK -- we speak protocol version %i, peer speeks %i. Aborting.\n", BRO_PROTOCOL_VERSION, proto_version)); __bro_openssl_shutdown(bc); free(data); goto reset_return; } else { D(("Protocols compatible, we speak version %i\n", BRO_PROTOCOL_VERSION)); } if (data_version != 0 && data_version != BRO_DATA_FORMAT_VERSION) { D(("EEEK -- we speak data format version %i, peer speeks %i. Aborting.\n", BRO_DATA_FORMAT_VERSION, data_version)); __bro_openssl_shutdown(bc); free(data); goto reset_return; } else { D(("Data formats compatible, we speak version %i\n", BRO_DATA_FORMAT_VERSION)); } bc->io_cache_maxsize = cache_size; D(("Receiver cache size set to %i entries.\n", cache_size)); free(data); bc->state->conn_state_peer = BRO_CONNSTATE_HANDSHAKE; D(("VERSION received, on %p, peer now in HANDSHAKE stage.\n")); } break; case BRO_MSG_SERIAL: { uint32 pre_serial; D(("Received MSQ_SERIAL\n")); pre_serial = __bro_buf_ptr_tell(bc->rx_buf); if (! io_read_chunk_size(bc, &chunk_size)) goto reset_return; if (! io_process_serialization(bc)) io_skip_chunk(bc->rx_buf, pre_serial, chunk_size); } break; case BRO_MSG_CAPTURE_FILTER: { uint32 pre_capture; D(("Received MSQ_CAPTURE_FILTER\n")); pre_capture = __bro_buf_ptr_tell(bc->rx_buf); if (! io_read_chunk_size(bc, &chunk_size)) goto reset_return; io_skip_chunk(bc->rx_buf, pre_capture, chunk_size); } break; case BRO_MSG_PHASE_DONE: /* No additional content for this one. */ switch (bc->state->conn_state_peer) { case BRO_CONNSTATE_HANDSHAKE: /* When we complete the handshake phase, it depends * on whether or not the peer has requested synced * state. If so, enter the sync phase, otherwise * we're up and running. */ if (bc->state->sync_state_requested) { bc->state->conn_state_peer = BRO_CONNSTATE_SYNC; D(("Phase done from peer on %p, sync requested, peer now in SYNC stage.\n", bc)); } else { bc->state->conn_state_peer = BRO_CONNSTATE_RUNNING; D(("Phase done from peer on %p, no sync requested, peer now in RUNNING stage.\n", bc)); } break; case BRO_CONNSTATE_SYNC: bc->state->conn_state_peer = BRO_CONNSTATE_RUNNING; D(("Phase done from peer on %p, peer now in RUNNING stage.\n", bc)); break; default: D(("Ignoring PHASE_DONE in conn state %i/%i on conn %p\n", bc->state->conn_state_self, bc->state->conn_state_peer, bc)); } break; case BRO_MSG_REQUEST_SYNC: { uchar *data; D(("Received MSQ_REQUEST_SYNC, peer now in SYNC stage.\n")); bc->state->sync_state_requested = 1; bc->state->conn_state_peer = BRO_CONNSTATE_SYNC; /* We need to read another chunk for the raw data. */ if (! io_read_chunk_size(bc, &chunk_size)) goto reset_return; if (! (data = malloc(sizeof(uchar) * chunk_size))) goto reset_return; if (! __bro_buf_read_data(bc->rx_buf, data, chunk_size)) { free(data); goto reset_return; } D(("Skipping sync interpretation\n")); free(data); break; } case BRO_MSG_CAPS: { uchar *data; D(("Received MSG_CAPS\n")); /* We need to read another chunk for the raw data. */ if (! io_read_chunk_size(bc, &chunk_size)) goto reset_return; if (! (data = malloc(sizeof(uchar) * chunk_size))) goto reset_return; if (! __bro_buf_read_data(bc->rx_buf, data, chunk_size)) { free(data); goto reset_return; } D(("Skipping capabilities interpretation\n")); free(data); break; } default: D(("Skipping unknown message type %i\n", msg_hdr.hdr_type)); break; } __bro_buf_consume(bc->rx_buf); result = TRUE; if ((bc->conn_flags & BRO_CFLAG_YIELD) && bc->state->conn_state_self == BRO_CONNSTATE_RUNNING && bc->state->conn_state_peer == BRO_CONNSTATE_RUNNING) break; } reset_return: __bro_buf_ptr_seek(bc->rx_buf, buf_off, SEEK_SET); D_RETURN_(result); }
int __bro_openssl_write(BroConn *bc, uchar *buf, uint buf_size) { int n; void *old_sig; D_ENTER; #ifdef BRO_DEBUG if (bro_debug_messages) { unsigned int i = 0; int last_hex = 0; D(("Sending %u bytes: ", buf_size)); for (i = 0; i < buf_size; i++) { if (buf[i] >= 32 && buf[i] <= 126) { printf("%s%c", last_hex ? " " : "", buf[i]); last_hex = 0; } else { printf(" 0x%.2x", buf[i]); last_hex = 1; } } printf("\n"); } #endif /* We may get a SIGPIPE if we write to a connection whose peer * died. Since we don't know the application context in which * we're running, we temporarily set the SIGPIPE handler to our * own and then set it back to the old one after we wrote. */ old_sig = signal(SIGPIPE, SIG_IGN); n = BIO_write(bc->bio, buf, buf_size); if (n <= 0) { if (BIO_should_retry(bc->bio)) { n = 0; goto error_return; } print_errors(); __bro_openssl_shutdown(bc); D(("Connection closed.\n")); n = -1; } BIO_flush(bc->bio); error_return: if (old_sig != SIG_ERR) signal(SIGPIPE, old_sig); D_RETURN_(n); }