/*---------------------------------------------------------------------*/ tree_cell * nasl_close_socket(lex_ctxt * lexic) { int soc; int type; int opt_len = sizeof(type); int e; soc = get_int_var_by_num(lexic, 0, -1); if(soc <= 4) { nasl_perror(lexic, "close(): invalid argument\n"); return NULL; } if ( fd_is_stream(soc) ) { return close_stream_connection(soc) < 0 ? NULL:FAKE_CELL; } e = getsockopt(soc, SOL_SOCKET, SO_TYPE, &type, &opt_len); if(e == 0 ) { if (type == SOCK_DGRAM) { rm_udp_data(lexic->script_infos, soc); return FAKE_CELL; } closesocket(soc); return FAKE_CELL; } else nasl_perror(lexic, "close(): invalid argument\n"); return NULL; }
/*---------------------------------------------------------------------*/ tree_cell * nasl_close_socket (lex_ctxt * lexic) { int soc; int type; unsigned int opt_len = sizeof (type); int e; soc = get_int_var_by_num (lexic, 0, -1); /* XXX: These are thoughts expressed on the openvas-devel mailing list 2008-08-06: * * nasl_close_socket seems to be the only place in nasl/nasl_socket.c where the * value of the socket filedescriptor is checked in this way. That in itself is * strange. Why only there? Also, why can't the socket fd be less than 4? I * could sort of understand 3 (0, 1, 2 are already taken by the standard * streams) but 4? Does the openvas server and/or the NASL interpreter guarantee * that at least one other file is open? * * My guess is that the check is there to prevent NASL scripts from closing file * descriptors needed by openvas/NASL which includes the ones it uses for * accessing the knowledgebase. If that's the case, then the test has too much * knowledge of the circumstances under which the NASL interpreter runs. It * should be moved to a separate function whose behavior can be influenced by * the program embedding the NASL interpreter. Other functions should probably * also check the descriptors. * * I also wonder whether the original code (disallowing any file descriptor <= 4) * actually was correct and the real defect is that open_sock_udp actually * returned 4. Under which circumstances does it actually do that? In my brief * tests with the stand-alone nasl interpreter the smallest number it returned * was 5. */ if (soc < 4) { nasl_perror (lexic, "close(): invalid argument\n"); return NULL; } if (fd_is_stream (soc)) return close_stream_connection (soc) < 0 ? NULL : FAKE_CELL; e = getsockopt (soc, SOL_SOCKET, SO_TYPE, &type, &opt_len); if (e == 0) { if (type == SOCK_DGRAM) { rm_udp_data (lexic->script_infos, soc); return FAKE_CELL; } close (soc); return FAKE_CELL; } else nasl_perror (lexic, "close(): invalid argument\n"); return NULL; }
tree_cell * nasl_socket_get_error (lex_ctxt * lexic) { int soc = get_int_var_by_num (lexic, 0, -1); tree_cell *retc; int err; if (soc < 0 || !fd_is_stream (soc)) return NULL; err = stream_get_err (soc); retc = alloc_typed_cell (CONST_INT); switch (err) { case 0: retc->x.i_val = NASL_ERR_NOERR; break; case ETIMEDOUT: retc->x.i_val = NASL_ERR_ETIMEDOUT; break; case EBADF: case EPIPE: #ifdef ECONNRESET case ECONNRESET: #endif #ifdef ENOTSOCK case ENOTSOCK: #endif retc->x.i_val = NASL_ERR_ECONNRESET; break; case ENETUNREACH: case EHOSTUNREACH: retc->x.i_val = NASL_ERR_EUNREACH; break; default: log_legacy_write ("Unknown error %d %s\n", err, strerror (err)); } return retc; }
tree_cell * nasl_send (lex_ctxt * lexic) { int soc = get_int_local_var_by_name (lexic, "socket", 0); char *data = get_str_local_var_by_name (lexic, "data"); int option = get_int_local_var_by_name (lexic, "option", 0); int length = get_int_local_var_by_name (lexic, "length", 0); int data_length = get_var_size_by_name (lexic, "data"); int n; tree_cell *retc; int type; unsigned int type_len = sizeof (type); if (soc <= 0 || data == NULL) { nasl_perror (lexic, "Syntax error with the send() function\n"); nasl_perror (lexic, "Correct syntax is : send(socket:<soc>, data:<data>\n"); return NULL; } if (length <= 0 || length > data_length) length = data_length; if (!fd_is_stream (soc) && getsockopt (soc, SOL_SOCKET, SO_TYPE, &type, &type_len) == 0 && type == SOCK_DGRAM) { n = send (soc, data, length, option); add_udp_data (lexic->script_infos, soc, data, length); } else n = nsend (soc, data, length, option); retc = alloc_tree_cell (0, NULL); retc->type = CONST_INT; retc->x.i_val = n; return retc; }
/* Fixme: Merge this into nasl_get_sock_info. */ tree_cell * nasl_get_source_port (lex_ctxt * lexic) { struct sockaddr_in ia; int s, fd; unsigned int l; tree_cell *retc; int type; unsigned int type_len = sizeof (type); s = get_int_var_by_num (lexic, 0, -1); if (s < 0) { nasl_perror (lexic, "get_source_port: missing socket parameter\n"); return NULL; } if (!fd_is_stream (s) && getsockopt (s, SOL_SOCKET, SO_TYPE, &type, &type_len) == 0 && type == SOCK_DGRAM) fd = s; else fd = openvas_get_socket_from_connection (s); if (fd < 0) { nasl_perror (lexic, "get_source_port: invalid socket parameter %d\n", s); return NULL; } l = sizeof (ia); if (getsockname (fd, (struct sockaddr *) &ia, &l) < 0) { nasl_perror (lexic, "get_source_port: getsockname(%d): %s\n", fd, strerror (errno)); return NULL; } retc = alloc_typed_cell (CONST_INT); retc->x.i_val = ntohs (ia.sin_port); return retc; }
tree_cell * nasl_recv_line(lex_ctxt * lexic) { int len = get_int_local_var_by_name(lexic, "length", -1); int soc = get_int_local_var_by_name(lexic, "socket", 0); int timeout = get_int_local_var_by_name(lexic, "timeout", -1); char * data; int new_len = 0; int n = 0; tree_cell * retc; time_t t1 = 0; if(timeout < 0) timeout = lexic->recv_timeout; if(len == -1 || soc <= 0) { nasl_perror(lexic, "recv_line: missing or undefined parameter length or soc\n"); return NULL; } if (timeout >= 0) /* sycalls are much more expensive than simple tests */ t1 = time(NULL); if ( fd_is_stream(soc) != 0 ) { int bufsz = stream_get_buffer_sz ( soc ); if ( bufsz <= 0 ) stream_set_buffer(soc, len + 1 ); } data = emalloc(len+1); for(;;) { int e = read_stream_connection_min(soc, data+n, 1, 1); if(e < 0) break; if(e == 0) { if( timeout >= 0 && time(NULL) - t1 < timeout) continue; else break; } n++; if((data[n-1] == '\n') || (n >= len))break; } if(n <= 0) { efree(&data); return NULL; } new_len = n; retc = alloc_tree_cell(0, NULL); retc->type = CONST_DATA; retc->size = new_len; retc->x.str_val = nasl_strndup(data, new_len); efree(&data); return retc; }
tree_cell * nasl_recv(lex_ctxt * lexic) { char * data; int len = get_int_local_var_by_name(lexic, "length", -1); int min_len = get_int_local_var_by_name(lexic, "min", -1); int soc = get_int_local_var_by_name(lexic, "socket", 0); int to = get_int_local_var_by_name(lexic, "timeout", lexic->recv_timeout); fd_set rd; struct timeval tv; int new_len = 0; tree_cell * retc; int type = -1, opt_len = sizeof(type); int e; if(len <= 0 || soc <= 0) return NULL; if (to <= 0) to = 5; tv.tv_sec = to; tv.tv_usec = 0; data = emalloc(len); if ( !fd_is_stream(soc) ) e = getsockopt(soc, SOL_SOCKET, SO_TYPE, &type, &opt_len); else e = -1; if(e == 0 && type == SOCK_DGRAM) { /* * As UDP packets may be lost, we retry up to 5 times */ int retries = 5; int i; tv.tv_sec = to / retries; tv.tv_usec = (to % retries) * 100000; for(i=0;i<retries;i++) { FD_ZERO(&rd); FD_SET(soc, &rd); if(!to || select(soc+1, &rd, NULL, NULL, &tv)>0) { int e; e = recv(soc, data+new_len, len-new_len, 0); if(e <= 0) { if(!new_len) { efree(&data); return NULL; } else break; } else new_len+=e; if(new_len >= len)break; break; /* UDP data is never fragmented */ } else { /* * The packet may have been lost en route - we resend it */ char * data; int len; data = get_udp_data(lexic->script_infos, soc, &len); if(data != NULL)send(soc, data, len, 0); tv.tv_sec = to / retries; tv.tv_usec = ( to % retries) * 100000; } } } else { int old = stream_set_timeout(soc, tv.tv_sec); new_len = read_stream_connection_min(soc, data, min_len, len); stream_set_timeout(soc, old); } if(new_len > 0) { retc = alloc_tree_cell(0, NULL); retc->type = CONST_DATA; retc->x.str_val = nasl_strndup(data, new_len); retc->size = new_len; efree(&data); return retc; } else { efree(&data); return NULL; } }