/* Timer callback */ static void on_sess_timer(pj_timer_heap_t *th, pj_timer_entry *te) { nat_detect_session *sess; sess = (nat_detect_session*) te->user_data; if (te->id == TIMER_DESTROY) { pj_grp_lock_acquire(sess->grp_lock); pj_ioqueue_unregister(sess->key); sess->key = NULL; sess->sock = PJ_INVALID_SOCKET; te->id = 0; pj_grp_lock_release(sess->grp_lock); sess_destroy(sess); } else if (te->id == TIMER_TEST) { pj_bool_t next_timer; pj_grp_lock_acquire(sess->grp_lock); next_timer = PJ_FALSE; if (sess->timer_executed == 0) { send_test(sess, ST_TEST_1, NULL, 0); next_timer = PJ_TRUE; } else if (sess->timer_executed == 1) { send_test(sess, ST_TEST_2, NULL, CHANGE_IP_PORT_FLAG); next_timer = PJ_TRUE; } else if (sess->timer_executed == 2) { send_test(sess, ST_TEST_3, NULL, CHANGE_PORT_FLAG); } else { pj_assert(!"Shouldn't have timer at this state"); } ++sess->timer_executed; if (next_timer) { pj_time_val delay = {0, TEST_INTERVAL}; pj_timer_heap_schedule(th, te, &delay); } else { te->id = 0; } pj_grp_lock_release(sess->grp_lock); } else { pj_assert(!"Invalid timer ID"); } }
int main(int argc, char *argv[]) { init_connection(); //monitor_connection(); //register_signals for (int i = 0; i < 100; i++) { send_test(); recv_test(); usleep(200000); } exit(EXIT_SUCCESS); }
/* * Callback upon request completion. */ static void on_request_complete(pj_stun_session *stun_sess, pj_status_t status, void *token, pj_stun_tx_data *tdata, const pj_stun_msg *response, const pj_sockaddr_t *src_addr, unsigned src_addr_len) { nat_detect_session *sess; pj_stun_sockaddr_attr *mattr = NULL; pj_stun_changed_addr_attr *ca = NULL; pj_uint32_t *tsx_id; int cmp; unsigned test_id; PJ_UNUSED_ARG(token); PJ_UNUSED_ARG(tdata); PJ_UNUSED_ARG(src_addr); PJ_UNUSED_ARG(src_addr_len); sess = (nat_detect_session*) pj_stun_session_get_user_data(stun_sess); pj_grp_lock_acquire(sess->grp_lock); /* Find errors in the response */ if (status == PJ_SUCCESS) { /* Check error message */ if (PJ_STUN_IS_ERROR_RESPONSE(response->hdr.type)) { pj_stun_errcode_attr *eattr; int err_code; eattr = (pj_stun_errcode_attr*) pj_stun_msg_find_attr(response, PJ_STUN_ATTR_ERROR_CODE, 0); if (eattr != NULL) err_code = eattr->err_code; else err_code = PJ_STUN_SC_SERVER_ERROR; status = PJ_STATUS_FROM_STUN_CODE(err_code); } else { /* Get MAPPED-ADDRESS or XOR-MAPPED-ADDRESS */ mattr = (pj_stun_sockaddr_attr*) pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR, 0); if (mattr == NULL) { mattr = (pj_stun_sockaddr_attr*) pj_stun_msg_find_attr(response, PJ_STUN_ATTR_MAPPED_ADDR, 0); } if (mattr == NULL) { status = PJNATH_ESTUNNOMAPPEDADDR; } /* Get CHANGED-ADDRESS attribute */ ca = (pj_stun_changed_addr_attr*) pj_stun_msg_find_attr(response, PJ_STUN_ATTR_CHANGED_ADDR, 0); if (ca == NULL) { status = PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_SERVER_ERROR); } } } /* Save the result */ tsx_id = (pj_uint32_t*) tdata->msg->hdr.tsx_id; test_id = tsx_id[2]; if (test_id >= ST_MAX) { PJ_LOG(4,(sess->pool->obj_name, "Invalid transaction ID %u in response", test_id)); end_session(sess, PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_SERVER_ERROR), PJ_STUN_NAT_TYPE_ERR_UNKNOWN); goto on_return; } PJ_LOG(5,(sess->pool->obj_name, "Completed %s, status=%d", test_names[test_id], status)); sess->result[test_id].complete = PJ_TRUE; sess->result[test_id].status = status; if (status == PJ_SUCCESS) { pj_memcpy(&sess->result[test_id].ma, &mattr->sockaddr.ipv4, sizeof(pj_sockaddr_in)); pj_memcpy(&sess->result[test_id].ca, &ca->sockaddr.ipv4, sizeof(pj_sockaddr_in)); } /* Send Test 1B only when Test 2 completes. Must not send Test 1B * before Test 2 completes to avoid creating mapping on the NAT. */ if (!sess->result[ST_TEST_1B].executed && sess->result[ST_TEST_2].complete && sess->result[ST_TEST_2].status != PJ_SUCCESS && sess->result[ST_TEST_1].complete && sess->result[ST_TEST_1].status == PJ_SUCCESS) { cmp = pj_memcmp(&sess->local_addr, &sess->result[ST_TEST_1].ma, sizeof(pj_sockaddr_in)); if (cmp != 0) send_test(sess, ST_TEST_1B, &sess->result[ST_TEST_1].ca, 0); } if (test_completed(sess)<3 || test_completed(sess)!=test_executed(sess)) goto on_return; /* Handle the test result according to RFC 3489 page 22: +--------+ | Test | | 1 | +--------+ | | V /\ /\ N / \ Y / \ Y +--------+ UDP <-------/Resp\--------->/ IP \------------->| Test | Blocked \ ? / \Same/ | 2 | \ / \? / +--------+ \/ \/ | | N | | V V /\ +--------+ Sym. N / \ | Test | UDP <---/Resp\ | 2 | Firewall \ ? / +--------+ \ / | \/ V |Y /\ /\ | Symmetric N / \ +--------+ N / \ V NAT <--- / IP \<-----| Test |<--- /Resp\ Open \Same/ | 1B | \ ? / Internet \? / +--------+ \ / \/ \/ | |Y | | | V | Full | Cone V /\ +--------+ / \ Y | Test |------>/Resp\---->Restricted | 3 | \ ? / +--------+ \ / \/ |N | Port +------>Restricted Figure 2: Flow for type discovery process */ switch (sess->result[ST_TEST_1].status) { case PJNATH_ESTUNTIMEDOUT: /* * Test 1 has timed-out. Conclude with NAT_TYPE_BLOCKED. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_BLOCKED); break; case PJ_SUCCESS: /* * Test 1 is successful. Further tests are needed to detect * NAT type. Compare the MAPPED-ADDRESS with the local address. */ cmp = pj_memcmp(&sess->local_addr, &sess->result[ST_TEST_1].ma, sizeof(pj_sockaddr_in)); if (cmp==0) { /* * MAPPED-ADDRESS and local address is equal. Need one more * test to determine NAT type. */ switch (sess->result[ST_TEST_2].status) { case PJ_SUCCESS: /* * Test 2 is also successful. We're in the open. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_OPEN); break; case PJNATH_ESTUNTIMEDOUT: /* * Test 2 has timed out. We're behind somekind of UDP * firewall. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_SYMMETRIC_UDP); break; default: /* * We've got other error with Test 2. */ end_session(sess, sess->result[ST_TEST_2].status, PJ_STUN_NAT_TYPE_ERR_UNKNOWN); break; } } else { /* * MAPPED-ADDRESS is different than local address. * We're behind NAT. */ switch (sess->result[ST_TEST_2].status) { case PJ_SUCCESS: /* * Test 2 is successful. We're behind a full-cone NAT. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_FULL_CONE); break; case PJNATH_ESTUNTIMEDOUT: /* * Test 2 has timed-out Check result of test 1B.. */ switch (sess->result[ST_TEST_1B].status) { case PJ_SUCCESS: /* * Compare the MAPPED-ADDRESS of test 1B with the * MAPPED-ADDRESS returned in test 1.. */ cmp = pj_memcmp(&sess->result[ST_TEST_1].ma, &sess->result[ST_TEST_1B].ma, sizeof(pj_sockaddr_in)); if (cmp != 0) { /* * MAPPED-ADDRESS is different, we're behind a * symmetric NAT. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_SYMMETRIC); } else { /* * MAPPED-ADDRESS is equal. We're behind a restricted * or port-restricted NAT, depending on the result of * test 3. */ switch (sess->result[ST_TEST_3].status) { case PJ_SUCCESS: /* * Test 3 is successful, we're behind a restricted * NAT. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_RESTRICTED); break; case PJNATH_ESTUNTIMEDOUT: /* * Test 3 failed, we're behind a port restricted * NAT. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_PORT_RESTRICTED); break; default: /* * Got other error with test 3. */ end_session(sess, sess->result[ST_TEST_3].status, PJ_STUN_NAT_TYPE_ERR_UNKNOWN); break; } } break; case PJNATH_ESTUNTIMEDOUT: /* * Strangely test 1B has failed. Maybe connectivity was * lost? Or perhaps port 3489 (the usual port number in * CHANGED-ADDRESS) is blocked? */ switch (sess->result[ST_TEST_3].status) { case PJ_SUCCESS: /* Although test 1B failed, test 3 was successful. * It could be that port 3489 is blocked, while the * NAT itself looks to be a Restricted one. */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_RESTRICTED); break; default: /* Can't distinguish between Symmetric and Port * Restricted, so set the type to Unknown */ end_session(sess, PJ_SUCCESS, PJ_STUN_NAT_TYPE_ERR_UNKNOWN); break; } break; default: /* * Got other error with test 1B. */ end_session(sess, sess->result[ST_TEST_1B].status, PJ_STUN_NAT_TYPE_ERR_UNKNOWN); break; } break; default: /* * We've got other error with Test 2. */ end_session(sess, sess->result[ST_TEST_2].status, PJ_STUN_NAT_TYPE_ERR_UNKNOWN); break; } } break; default: /* * We've got other error with Test 1. */ end_session(sess, sess->result[ST_TEST_1].status, PJ_STUN_NAT_TYPE_ERR_UNKNOWN); break; } on_return: pj_grp_lock_release(sess->grp_lock); }
int main(int argc, char *argv[]) { int sockfd, numbytes; char buf[MAXDATASIZE]; struct hostent *he; // connectors address information: struct sockaddr_in their_addr; // if no command line argument supplied: if(argc != 2) { fprintf(stderr, "Client-Usage: %s the_client_hostname\n", argv[0]); exit(EXIT_FAILURE); } // get the host info if((he=gethostbyname(argv[1])) == NULL) { perror("gethostbyname()"); exit(EXIT_FAILURE); } printf("Client-The remote host is: %s\n", argv[1]); if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket()"); exit(EXIT_FAILURE); } printf("Client-The socket() sockfd is %d\n", sockfd); // short, network byte order: printf("Server-Using %s and port %d...\n", argv[1], PORT); // host byte order their_addr.sin_family = AF_INET; their_addr.sin_port = htons(PORT); their_addr.sin_addr = *((struct in_addr *)he->h_addr); // zero the rest of the struct memset(&(their_addr.sin_zero), '\0', 8); if(connect(sockfd, (struct sockaddr *) &their_addr, sizeof(struct sockaddr) ) == -1) { perror("connect()"); exit(EXIT_FAILURE); } printf("Client-The connect() is OK...\n"); // Zauberwort senden: char alohomora[] = "auth\n"; if ((numbytes = send(sockfd, alohomora, strlen(alohomora), 0)) < 0) { perror("sending \"auth\\n\" failed"); exit(EXIT_FAILURE); } // Benutzernamen einlesen: char * username[MAX_USERNAME]; printf("Benutzername: "); fgets(username, MAX_USERNAME, stdin); // Benutzernamen senden: send(sockfd, username, strlen(username), 0); // Passwort einlesen: char * password = (char *) malloc(_PASSWORD_LEN); readpassphrase("Passwort: ", password, sizeof(password), 0); // Passwort senden // OMG - IM KLARTEXT!!!! Dafür stirbt gerade eine Nyan Katze. send(sockfd, password, strlen(password), 0); // Antwort von Authentifizierung empfangen: if((numbytes = recv(sockfd, buf, MAX_SIZE, 0)) < 0) { perror("recv()"); exit(EXIT_FAILURE); } else { printf("=> %s", buf); } char cmd = ' '; while (cmd != '0') { print_auswahlmenu(); cmd = fgetc(stdin); switch (cmd) { case '0': break; case 't': send_test(sockfd); break; } } /*buf[numbytes] = '\0';*/ printf("Client-Closing sockfd\n"); close(sockfd); return EXIT_SUCCESS; }