📄 pptp_ctrl.c
字号:
/* fill in the phone number if it was specified */ if (phonenr) { strncpy(packet.phone_num, phonenr, sizeof(packet.phone_num)); packet.phone_len = strlen(phonenr); if( packet.phone_len > sizeof(packet.phone_num)) packet.phone_len = sizeof(packet.phone_num); packet.phone_len = hton16 (packet.phone_len); } if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) { pptp_reset_timer(); call->state.pns = PNS_WAIT_REPLY; /* and add it to the call vector */ vector_insert(conn->call, i, call); return call; } else { /* oops, unsuccessful. Deallocate. */ free(call); return NULL; }}/*** pptp_call_close **********************************************************/void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call){ struct pptp_call_clear_rqst rqst = { PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_RQST), 0, 0 }; assert(conn && conn->call); assert(call); assert(vector_contains(conn->call, call->call_id)); /* haven't thought about PAC yet */ assert(call->call_type == PPTP_CALL_PNS); assert(call->state.pns != PNS_IDLE); rqst.call_id = hton16(call->call_id); /* don't check state against WAIT_DISCONNECT... allow multiple disconnect * requests to be made. */ pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst)); pptp_reset_timer(); call->state.pns = PNS_WAIT_DISCONNECT; /* call structure will be freed when we have confirmation of disconnect. */}/*** hard close ***************************************************************/void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call){ assert(conn && conn->call); assert(call); assert(vector_contains(conn->call, call->call_id)); /* notify */ if (call->callback != NULL) call->callback(conn, call, CALL_CLOSE_DONE); /* deallocate */ vector_remove(conn->call, call->call_id); free(call);}/*** this is a soft close *****************************************************/void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason){ struct pptp_stop_ctrl_conn rqst = { PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST), hton8(close_reason), 0, 0 }; int i; assert(conn && conn->call); /* avoid repeated close attempts */ if (conn->conn_state == CONN_IDLE || conn->conn_state == CONN_WAIT_STOP_REPLY) return; /* close open calls, if any */ for (i = 0; i < vector_size(conn->call); i++) pptp_call_close(conn, vector_get_Nth(conn->call, i)); /* now close connection */ log("Closing PPTP connection"); pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst)); pptp_reset_timer(); /* wait 60 seconds for reply */ conn->conn_state = CONN_WAIT_STOP_REPLY; return;}/*** this is a hard close *****************************************************/void pptp_conn_destroy(PPTP_CONN * conn){ int i; assert(conn != NULL); assert(conn->call != NULL); /* destroy all open calls */ for (i = 0; i < vector_size(conn->call); i++) pptp_call_destroy(conn, vector_get_Nth(conn->call, i)); /* notify */ if (conn->callback != NULL) conn->callback(conn, CONN_CLOSE_DONE); sigpipe_close(); close(conn->inet_sock); /* deallocate */ vector_destroy(conn->call); free(conn);}/*** Deal with messages, in a non-blocking manner * Add file descriptors used by pptp to fd_set. */void pptp_fd_set(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set, int * max_fd){ assert(conn && conn->call); /* Add fd to write_set if there are outstanding writes. */ if (conn->write_size > 0) FD_SET(conn->inet_sock, write_set); /* Always add fd to read_set. (always want something to read) */ FD_SET(conn->inet_sock, read_set); if (*max_fd < conn->inet_sock) *max_fd = conn->inet_sock; /* Add signal pipe file descriptor to set */ int sig_fd = sigpipe_fd(); FD_SET(sig_fd, read_set); if (*max_fd < sig_fd) *max_fd = sig_fd;}/*** handle any pptp file descriptors set in fd_set, and clear them ***********/int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set){ int r = 0; assert(conn && conn->call); /* Check for signals */ if (FD_ISSET(sigpipe_fd(), read_set)) { if (sigpipe_read() == SIGALRM) pptp_handle_timer(); FD_CLR(sigpipe_fd(), read_set); } /* Check write_set could be set. */ if (FD_ISSET(conn->inet_sock, write_set)) { FD_CLR(conn->inet_sock, write_set); if (conn->write_size > 0) r = pptp_write_some(conn);/* write as much as we can without blocking */ } /* Check read_set */ if (r >= 0 && FD_ISSET(conn->inet_sock, read_set)) { void *buffer; size_t size; FD_CLR(conn->inet_sock, read_set); r = pptp_read_some(conn); /* read as much as we can without blocking */ if (r < 0) return r; /* make packets of the buffer, while we can. */ while (r >= 0 && pptp_make_packet(conn, &buffer, &size)) { r = pptp_dispatch_packet(conn, buffer, size); free(buffer); } } /* That's all, folks. Simple, eh? */ return r;}/*** Non-blocking write *******************************************************/int pptp_write_some(PPTP_CONN * conn) { ssize_t retval; assert(conn && conn->call); retval = write(conn->inet_sock, conn->write_buffer, conn->write_size); if (retval < 0) { /* error. */ if (errno == EAGAIN || errno == EINTR) { return 0; } else { /* a real error */ log("write error: %s", strerror(errno)); return -1; } } assert(retval <= conn->write_size); conn->write_size -= retval; memmove(conn->write_buffer, conn->write_buffer + retval, conn->write_size); ctrlp_rep(conn->write_buffer, retval, 0); return 0;}/*** Non-blocking read ********************************************************/int pptp_read_some(PPTP_CONN * conn){ ssize_t retval; assert(conn && conn->call); if (conn->read_size == conn->read_alloc) { /* need to alloc more memory */ char *new_buffer = realloc(conn->read_buffer, sizeof(*(conn->read_buffer)) * conn->read_alloc * 2); if (new_buffer == NULL) { log("Out of memory"); return -1; } conn->read_alloc *= 2; conn->read_buffer = new_buffer; } retval = read(conn->inet_sock, conn->read_buffer + conn->read_size, conn->read_alloc - conn->read_size); if (retval == 0) { log("read returned zero, peer has closed"); return -1; } if (retval < 0) { if (errno == EINTR || errno == EAGAIN) return 0; else { /* a real error */ log("read error: %s", strerror(errno)); return -1; } } conn->read_size += retval; assert(conn->read_size <= conn->read_alloc); return 0;}/*** Packet formation *********************************************************/int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size){ struct pptp_header *header; size_t bad_bytes = 0; assert(conn && conn->call); assert(buf != NULL); assert(size != NULL); /* Give up unless there are at least sizeof(pptp_header) bytes */ while ((conn->read_size-bad_bytes) >= sizeof(struct pptp_header)) { /* Throw out bytes until we have a valid header. */ header = (struct pptp_header *) (conn->read_buffer + bad_bytes); if (ntoh32(header->magic) != PPTP_MAGIC) goto throwitout; if (ntoh16(header->reserved0) != 0) log("reserved0 field is not zero! (0x%x) Cisco feature? \n", ntoh16(header->reserved0)); if (ntoh16(header->length) < sizeof(struct pptp_header)) goto throwitout; if (ntoh16(header->length) > PPTP_CTRL_SIZE_MAX) goto throwitout; /* well. I guess it's good. Let's see if we've got it all. */ if (ntoh16(header->length) > (conn->read_size-bad_bytes)) /* nope. Let's wait until we've got it, then. */ goto flushbadbytes; /* One last check: */ if ((ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL) && (ntoh16(header->length) != PPTP_CTRL_SIZE(ntoh16(header->ctrl_type)))) goto throwitout; /* well, I guess we've got it. */ *size = ntoh16(header->length); *buf = malloc(*size); if (*buf == NULL) { log("Out of memory."); return 0; /* ack! */ } memcpy(*buf, conn->read_buffer + bad_bytes, *size); /* Delete this packet from the read_buffer. */ conn->read_size -= (bad_bytes + *size); memmove(conn->read_buffer, conn->read_buffer + bad_bytes + *size, conn->read_size); if (bad_bytes > 0) log("%lu bad bytes thrown away.", (unsigned long) bad_bytes); return 1;throwitout: bad_bytes++; }flushbadbytes: /* no more packets. Let's get rid of those bad bytes */ conn->read_size -= bad_bytes; memmove(conn->read_buffer, conn->read_buffer + bad_bytes, conn->read_size); if (bad_bytes > 0) log("%lu bad bytes thrown away.", (unsigned long) bad_bytes); return 0;}/*** pptp_send_ctrl_packet ****************************************************/int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size){ assert(conn && conn->call); assert(buffer); if( conn->write_size > 0) pptp_write_some( conn); if( conn->write_size == 0) { ssize_t retval; retval = write(conn->inet_sock, buffer, size); if (retval < 0) { /* error. */ if (errno == EAGAIN || errno == EINTR) { /* ignore */; retval = 0; } else { /* a real error */ log("write error: %s", strerror(errno)); pptp_conn_destroy(conn); /* shut down fast. */ return 0; } } ctrlp_rep( buffer, retval, 0); size -= retval; if( size <= 0) return 1; } /* Shove anything not written into the write buffer */ if (conn->write_size + size > conn->write_alloc) { /* need more memory */ char *new_buffer = realloc(conn->write_buffer, sizeof(*(conn->write_buffer)) * conn->write_alloc * 2); if (new_buffer == NULL) { log("Out of memory"); return 0; } conn->write_alloc *= 2; conn->write_buffer = new_buffer; } memcpy(conn->write_buffer + conn->write_size, buffer, size); conn->write_size += size; ctrlp_rep( buffer,size,1); return 1;}/*** Packet Dispatch **********************************************************/int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size){ int r = 0; struct pptp_header *header = (struct pptp_header *)buffer; assert(conn && conn->call); assert(buffer); assert(ntoh32(header->magic) == PPTP_MAGIC); assert(ntoh16(header->length) == size); switch (ntoh16(header->pptp_type)) { case PPTP_MESSAGE_CONTROL: r = ctrlp_disp(conn, buffer, size); break; case PPTP_MESSAGE_MANAGE: /* MANAGEMENT messages aren't even part of the spec right now. */ log("PPTP management message received, but not understood."); break; default: log("Unknown PPTP control message type received: %u", (unsigned int) ntoh16(header->pptp_type)); break; } return r;}/*** log echo request/replies *************************************************/static void logecho( int type){ /* hack to stop flooding the log files (the most interesting part is right * after the connection built-up) */ if( nlogecho > 0) { log( "Echo Re%s received.", type == PPTP_ECHO_RQST ? "quest" :"ply"); if( --nlogecho == 0) log("no more Echo Reply/Request packets will be reported."); }}/*** pptp_dispatch_ctrl_packet ************************************************/int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size){ struct pptp_header *header = (struct pptp_header *)buffer; u_int8_t close_reason = PPTP_STOP_NONE; assert(conn && conn->call); assert(buffer); assert(ntoh32(header->magic) == PPTP_MAGIC); assert(ntoh16(header->length) == size); assert(ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL); if (size < PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))) { log("Invalid packet received [type: %d; length: %d].", (int) ntoh16(header->ctrl_type), (int) size); return 0; } switch (ntoh16(header->ctrl_type)) { /* ----------- STANDARD Start-Session MESSAGES ------------ */ case PPTP_START_CTRL_CONN_RQST: { struct pptp_start_ctrl_conn *packet = (struct pptp_start_ctrl_conn *) buffer; struct pptp_start_ctrl_conn reply = { PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY), hton16(PPTP_VERSION), 0, 0, hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP), hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION), PPTP_HOSTNAME, PPTP_VENDOR }; int idx, rc; log("Received Start Control Connection Request"); /* fix this packet, if necessary */ idx = get_quirk_index(); if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) { if ((rc = pptp_fixups[idx].start_ctrl_conn(&reply))) warn("calling the start_ctrl_conn hook failed (%d)", rc); } if (conn->conn_state == CONN_IDLE) { if (ntoh16(packet->version) < PPTP_VERSION) { /* Can't support this (earlier) PPTP_VERSION */ reply.version = packet->version; /* protocol version not supported */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -