Beispiel #1
0
/*********************************************************************
*
*       _Listen
*
*  Function description
*    This function is called from the FTP server module if the client
*    uses passive FTP. It creates socket and searches for a free port
*    which can be used for the data connection.
*
*  Return value
*    > 0   Socket descriptor
*    NULL  Error
*/
static FTPS_SOCKET _Listen(FTPS_SOCKET CtrlSocket, U16 *pPort, U8 * pIPAddr) {
  struct sockaddr_in addr;
  U16  Port;
  int  DataSock;
  int  AddrSize;

  addr.sin_family = AF_INET;
  addr.sin_port   = 0;                          // Let Stack find a free port
  addr.sin_addr.s_addr = INADDR_ANY;
  DataSock = _socket(AF_INET, SOCK_STREAM, 0);  // Create a new socket for data connection to the client
  if(DataSock == SOCKET_ERROR) {                // Socket created?
    return NULL;
  }
  _bind(DataSock, (struct sockaddr *)&addr, sizeof(addr));
  _listen(DataSock, 1);
  //
  //  Get port number stack has assigned
  //
  AddrSize = sizeof(struct sockaddr_in);
  _getsockname((long)DataSock, (struct sockaddr *)&addr, &AddrSize);
  Port = htons(addr.sin_port);
  *pPort = Port;
  _getsockname((long)CtrlSocket, (struct sockaddr *)&addr, &AddrSize);
  Port = htons(addr.sin_port);
  *pIPAddr++ = addr.sin_addr.s_addr;
  *pIPAddr++ = addr.sin_addr.s_addr >> 8;
  *pIPAddr++ = addr.sin_addr.s_addr >> 16;
  *pIPAddr   = addr.sin_addr.s_addr >> 24;
  return (FTPS_SOCKET)DataSock;
}
Beispiel #2
0
/*
 * Usage:
 *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
 *
 * Creates, registers, and returns a (rpc) tcp based transporter.
 * Once *xprt is initialized, it is registered as a transporter
 * see (svc.h, xprt_register).  This routine returns
 * a NULL if a problem occurred.
 *
 * The filedescriptor passed in is expected to refer to a bound, but
 * not yet connected socket.
 *
 * Since streams do buffered io similar to stdio, the caller can specify
 * how big the send and receive buffers are via the second and third parms;
 * 0 => use the system default.
 */
SVCXPRT *
svc_vc_create(int fd, u_int sendsize, u_int recvsize)
{
	SVCXPRT *xprt = NULL;
	struct cf_rendezvous *r = NULL;
	struct __rpc_sockinfo si;
	struct sockaddr_storage sslocal;
	socklen_t slen;

	if (!__rpc_fd2sockinfo(fd, &si))
		return NULL;

	r = mem_alloc(sizeof(*r));
	if (r == NULL) {
		warnx("svc_vc_create: out of memory");
		goto cleanup_svc_vc_create;
	}
	r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
	r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
	r->maxrec = __svc_maxrec;
	xprt = mem_alloc(sizeof(SVCXPRT));
	if (xprt == NULL) {
		warnx("svc_vc_create: out of memory");
		goto cleanup_svc_vc_create;
	}
	xprt->xp_tp = NULL;
	xprt->xp_p1 = r;
	xprt->xp_p2 = NULL;
	xprt->xp_p3 = NULL;
	xprt->xp_verf = _null_auth;
	svc_vc_rendezvous_ops(xprt);
	xprt->xp_port = (u_short)-1;	/* It is the rendezvouser */
	xprt->xp_fd = fd;

	slen = sizeof (struct sockaddr_storage);
	if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
		warnx("svc_vc_create: could not retrieve local addr");
		goto cleanup_svc_vc_create;
	}

	xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len;
	xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
	if (xprt->xp_ltaddr.buf == NULL) {
		warnx("svc_vc_create: no mem for local addr");
		goto cleanup_svc_vc_create;
	}
	memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);

	xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
	xprt_register(xprt);
	return (xprt);
cleanup_svc_vc_create:
	if (xprt)
		mem_free(xprt, sizeof(*xprt));
	if (r != NULL)
		mem_free(r, sizeof(*r));
	return (NULL);
}
Beispiel #3
0
/*
 * Like svtcp_create(), except the routine takes any *open* UNIX file
 * descriptor as its first input.
 */
SVCXPRT *
svc_fd_create(int fd, u_int sendsize, u_int recvsize)
{
	struct sockaddr_storage ss;
	socklen_t slen;
	SVCXPRT *ret;

	assert(fd != -1);

	ret = makefd_xprt(fd, sendsize, recvsize);
	if (ret == NULL)
		return NULL;

	slen = sizeof (struct sockaddr_storage);
	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
		warnx("svc_fd_create: could not retrieve local addr");
		goto freedata;
	}
	ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len;
	ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len);
	if (ret->xp_ltaddr.buf == NULL) {
		warnx("svc_fd_create: no mem for local addr");
		goto freedata;
	}
	memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len);

	slen = sizeof (struct sockaddr_storage);
	if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
		warnx("svc_fd_create: could not retrieve remote addr");
		goto freedata;
	}
	ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len;
	ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len);
	if (ret->xp_rtaddr.buf == NULL) {
		warnx("svc_fd_create: no mem for local addr");
		goto freedata;
	}
	memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len);
#ifdef PORTMAP
	if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) {
		ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf;
		ret->xp_addrlen = sizeof (struct sockaddr_in);
	}
#endif				/* PORTMAP */

	return ret;

freedata:
	if (ret->xp_ltaddr.buf != NULL)
		mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);

	return NULL;
}
Beispiel #4
0
void write_tcp( tcp_t *tcp, int len )
{
	if(len < sizeof(tcp_t)) {
	  D(bug("<%d> Too small tcp packet(%d) on unknown slot, dropped\r\n", -1, len));
		return;
	}
	uint16 src_port = ntohs(tcp->src_port);
	uint16 dest_port = ntohs(tcp->dest_port);

	BOOL ok = true;
	BOOL handle_data = false;
	BOOL initiate_read = false;

	EnterCriticalSection( &tcp_section );

	int t = find_socket( src_port, dest_port );

	if(t < 0) {
		t = alloc_new_socket( src_port, dest_port, ntohl(tcp->ip.dest) );
		ok = t >= 0;
	}

	if(ok) {
		D(bug("<%d> write_tcp %d bytes from port %d to port %d\r\n", t, len, src_port, dest_port));
	} else {
		D(bug("<%d> FAILED write_tcp %d bytes from port %d to port %d\r\n", t, len, src_port, dest_port));
	}

	if( ok && ISSET(tcp->flags,RST) ) {
		D(bug("<%d> RST set, resetting socket\r\n", t));
		if( sockets[t].s != INVALID_SOCKET ) {
			D(bug("<%d> doing an extra shutdown (ie4)\r\n", t));
			_shutdown( sockets[t].s, SD_BOTH );
		}
		free_socket( t );
		ok = false;
	}

	if(ok) {
		D(bug("<%d> State machine start = %s\r\n", t, STATENAME(sockets[t].state)));

		// always update receive window
		sockets[t].mac_window = ntohs(tcp->window);

		int header_len = tcp->header_len >> 2;
		int option_bytes = header_len - 20;
		char *data = (char *)tcp + sizeof(tcp_t) + option_bytes;
		int dlen = len - sizeof(tcp_t) - option_bytes;

		if( !ISSET(tcp->flags,ACK) ) {
			D(bug("<%d> ACK not set\r\n", t));
		}
		if( ISSET(tcp->flags,SYN) ) {
			D(bug("<%d> SYN set\r\n", t));

			// Note that some options are valid even if there is no SYN.
			// I don't care about those however.

			uint32 new_mss;
			process_options( t, (uint8 *)data - option_bytes, option_bytes, new_mss );
			if(new_mss) {
				sockets[t].mac_mss = (int)new_mss;
				if( new_mss < sockets[t].buffers_read[0].len ) {
					sockets[t].buffers_read[0].len = new_mss;
				}
				D(bug("<%d> Max segment size set to %d\r\n", t, new_mss));
			}
		}
		if( ISSET(tcp->flags,FIN) ) {
			D(bug("<%d> FIN set\r\n", t));
		}

		// The sequence number Mac expects to see next time.
		sockets[t].mac_ack = ntohl(tcp->ack);

		D(bug("<%d> From Mac: Seq=%d, Ack=%d, window=%d, router Seq=%d\r\n", t, ntohl(tcp->seq), sockets[t].mac_ack, sockets[t].mac_window, sockets[t].seq_out));

		if( sockets[t].stream_to_mac_stalled_until && 
				sockets[t].mac_ack == sockets[t].seq_out &&
				(sockets[t].state == ESTABLISHED || sockets[t].state == CLOSE_WAIT) )
		{
			if( has_mac_read_space(t) ) {
				initiate_read = true;
				sockets[t].stream_to_mac_stalled_until = 0;
				D(bug("<%d> read resumed, mac can accept more data\r\n", t));
			}
		}

		switch( sockets[t].state ) {
			case CLOSED:
				sockets[t].src_port = src_port;
				sockets[t].dest_port = dest_port;
				sockets[t].ip_src = ntohl(tcp->ip.src);
				sockets[t].ip_dest = ntohl(tcp->ip.dest);

				if( ISSET(tcp->flags,SYN) ) {

					sockets[t].seq_out = 0x00000001;
					sockets[t].seq_in = ntohl(tcp->seq) + 1;

					_WSAResetEvent( sockets[t].ev );
					if( SOCKET_ERROR == _WSAEventSelect( sockets[t].s, sockets[t].ev, FD_CONNECT | FD_CLOSE ) ) {
						D(bug("<%d> WSAEventSelect() failed with error code %d\r\n", t, _WSAGetLastError()));
					}

				  D(bug("<%d> connecting local port %d to remote %s:%d\r\n", t, src_port, _inet_ntoa(sockets[t].from.sin_addr), dest_port));

					sockets[t].state = LISTEN;
					if( _WSAConnect(
						sockets[t].s,
						(const struct sockaddr *)&sockets[t].from,
						sockets[t].from_len,
						NULL, NULL,
						NULL, NULL
					) == SOCKET_ERROR )
					{
						int connect_error = _WSAGetLastError();
						if( connect_error == WSAEWOULDBLOCK ) {
							D(bug("<%d> WSAConnect() i/o pending.\r\n", t));
						} else {
							D(bug("<%d> WSAConnect() failed with error %d.\r\n", t, connect_error));
						}
					} else {
						D(bug("<%d> WSAConnect() ok.\r\n", t));
					}
				} else {
					if( ISSET(tcp->flags,FIN) ) {
						D(bug("<%d> No SYN but FIN on a closed socket.\r\n", t));
						free_socket(t);
					} else {
						D(bug("<%d> No SYN on a closed socket. resetting.\r\n", t));
						free_socket(t);
					}
				}
				break;
			case LISTEN:
				// handled in connect callback
				break;
			case SYN_SENT:
				if( ISSET(tcp->flags,SYN) && ISSET(tcp->flags,ACK) ) {
					sockets[t].seq_in = ntohl(tcp->seq) + 1;
					tcp_reply( ACK, t );
					sockets[t].state = ESTABLISHED;
					initiate_read = true;
					sockets[t].accept_more_data_from_mac = true;
					sockets[t].time_wait = 0;
				} else if( ISSET(tcp->flags,SYN) ) {
					sockets[t].seq_in = ntohl(tcp->seq) + 1;
					tcp_reply( ACK|SYN, t );
					sockets[t].seq_out++;
					sockets[t].state = SYN_RCVD;
					sockets[t].time_wait = 0;
				} else if( ISSET(tcp->flags,ACK) ) {
					// What was the bright idea here.
					D(bug("<%d> State is SYN_SENT, but got only ACK from Mac??\r\n", t));
					sockets[t].state = FINWAIT_2;
					sockets[t].time_wait = 0;
				}
				break;
			case SYN_RCVD:
				if( ISSET(tcp->flags,ACK) ) {
					sockets[t].state = ESTABLISHED;
					handle_data = true;
					initiate_read = true;
					sockets[t].accept_more_data_from_mac = true;
				}
				break;
			case ESTABLISHED:
				if( ISSET(tcp->flags,FIN) ) {
					sockets[t].seq_in++;
					tcp_reply( ACK, t );
					_shutdown( sockets[t].s, SD_SEND );
					sockets[t].state = CLOSE_WAIT;
				}
				handle_data = true;
				break;
			case CLOSE_WAIT:
				// handled in tcp_read_completion
				break;
			case LAST_ACK:
				if( ISSET(tcp->flags,ACK) ) {
					D(bug("<%d> LAST_ACK received, socket closed\r\n", t));
					free_socket( t );
				}
				break;
			case FINWAIT_1:
				if( ISSET(tcp->flags,FIN) && ISSET(tcp->flags,ACK) ) {
					sockets[t].seq_in++;
					tcp_reply( ACK, t );
					if(sockets[t].remote_closed) {
						_closesocket(sockets[t].s);
						sockets[t].s = INVALID_SOCKET;
					} else {
						_shutdown( sockets[t].s, SD_SEND );
					}
					sockets[t].state = TIME_WAIT;
					sockets[t].time_wait = GetTickCount() + 2 * sockets[t].msl;
				} else if( ISSET(tcp->flags,FIN) ) {
					sockets[t].seq_in++;
					tcp_reply( ACK, t );
					if(sockets[t].remote_closed) {
						_closesocket(sockets[t].s);
						sockets[t].s = INVALID_SOCKET;
					} else {
						_shutdown( sockets[t].s, SD_SEND );
					}
					sockets[t].state = CLOSING;
				} else if( ISSET(tcp->flags,ACK) ) {
					sockets[t].state = FINWAIT_2;
				}
				break;
			case FINWAIT_2:
				if( ISSET(tcp->flags,FIN) ) {
					sockets[t].seq_in++;
					tcp_reply( ACK, t );
					if(sockets[t].remote_closed) {
						_closesocket(sockets[t].s);
						sockets[t].s = INVALID_SOCKET;
					} else {
						_shutdown( sockets[t].s, SD_SEND );
					}
					sockets[t].state = TIME_WAIT;
					sockets[t].time_wait = GetTickCount() + 2 * sockets[t].msl;
				}
				break;
			case CLOSING:
				if( ISSET(tcp->flags,ACK) ) {
					sockets[t].state = TIME_WAIT;
					sockets[t].time_wait = GetTickCount() + 2 * sockets[t].msl;
				}
				break;
			case TIME_WAIT:
				// Catching stray packets: wait MSL * 2 seconds, -> CLOSED
				// Timer already set since we might not get here at all.
				// I'm using exceptionally low MSL value (5 secs).
				D(bug("<%d> time wait, datagram discarded\r\n", t));
				break;
		}

		// The "t" descriptor may already be freed. However, it's safe
		// to peek the state value inside the critical section.
		D(bug("<%d> State machine end = %s\r\n", t, STATENAME(sockets[t].state)));

		D(bug("<%d> handle_data=%d, initiate_read=%d\r\n", t, handle_data, initiate_read));

		if( handle_data && dlen && sockets[t].accept_more_data_from_mac ) {
			if( sockets[t].seq_in != ntohl(tcp->seq) ) {
				D(bug("<%d> dropping duplicate datagram seq=%d, expected=%d\r\n", t, ntohl(tcp->seq), sockets[t].seq_in));
			} else {
				set_ttl( t, tcp->ip.ttl );

				struct sockaddr_in to;
				memset( &to, 0, sizeof(to) );
				to.sin_family = AF_INET;
				to.sin_port = tcp->dest_port;
				to.sin_addr.s_addr = tcp->ip.dest;

				D(bug("<%d> sending %d bytes to remote host\r\n", t, dlen));

				sockets[t].accept_more_data_from_mac = false;

				if( dlen > MAX_SEGMENT_SIZE ) {
					D(bug("<%d> IMPOSSIBLE: b_send() dropped %d bytes! \r\n", t, dlen-MAX_SEGMENT_SIZE));
					dlen = MAX_SEGMENT_SIZE;
				}

				memcpy( sockets[t].buffers_write[0].buf, data, dlen );

				sockets[t].buffers_write[0].len = dlen;
				sockets[t].bytes_remaining_to_send = dlen;
				sockets[t].bytes_to_send = dlen;

				bool send_now = false;
				if( ISSET(tcp->flags,PSH) ) {
					send_now = true;
				} else {
					// todo -- delayed send
					send_now = true;
				}
				
				if(send_now) {

					// Patch ftp server or client address if needed.

					int lst = 1;
					bool is_pasv;
					uint16 ftp_data_port = 0;

					if(ftp_is_ftp_port(sockets[t].src_port)) {
						// Local ftp server may be entering to passive mode.
						is_pasv = true;
						ftp_parse_port_command( 
							sockets[t].buffers_write[0].buf,
							dlen,
							ftp_data_port,
							is_pasv
						);
					} else if(ftp_is_ftp_port(sockets[t].dest_port)) {
						// Local ftp client may be using port command.
						is_pasv = false;
						ftp_parse_port_command( 
							sockets[t].buffers_write[0].buf,
							dlen,
							ftp_data_port,
							is_pasv
						);
					}

					if(ftp_data_port) {
						D(bug("<%d> ftp %s command detected, port %d\r\n", t, (is_pasv ? "SERVER PASV REPLY" : "CLIENT PORT"), ftp_data_port ));

						// Note: for security reasons, only allow incoming connection from sockets[t].ip_dest
						lst = alloc_listen_socket( ftp_data_port, sockets[t].ip_dest, 0/*iface*/, true );

						if(lst < 0) {
							D(bug("<%d> no more free slots\r\n", t));
						} else {
							// First start listening (need to know the local name later)
							tcp_start_listen( lst );

							// When t is closed, lst must be closed too.
							sockets[t].child = lst;
							l_sockets[lst].parent = t;

							// Find out the local name
							struct sockaddr_in name;
							int namelen = sizeof(name);
							memset( &name, 0, sizeof(name) );
							if( _getsockname( sockets[t].s, (struct sockaddr *)&name, &namelen ) == SOCKET_ERROR ) {
								D(bug("_getsockname() failed, error=%d\r\n", _WSAGetLastError() ));
							}

							ftp_modify_port_command( 
								sockets[t].buffers_write[0].buf,
								dlen,
								MAX_SEGMENT_SIZE,
								ntohl(name.sin_addr.s_addr),
								ftp_data_port,
								is_pasv
							);

							sockets[t].buffers_write[0].len = dlen;
							sockets[t].bytes_remaining_to_send = dlen;
							// Do not change "bytes_to_send" field as it is used for ack calculation
						}
					} // end of ftp patch

					if(!b_send(t)) {
						// on error, close the ftp data listening socket if one was created
						if(lst >= 0) {
							D(bug("[%d] closing listening port %d after write error\r\n", t, l_sockets[lst].port));
							_closesocket( l_sockets[lst].s );
							l_sockets[lst].s = INVALID_SOCKET;
							l_sockets[lst].port = 0;
							l_sockets[lst].ip = 0;
							l_sockets[lst].parent = -1;
							sockets[t].child = -1;
						}
					}
				}
			}
		}

		if(initiate_read) {
			if(!b_recfrom(t)) {
				// post icmp error message
			}
		}
	}

	LeaveCriticalSection( &tcp_section );
}
Beispiel #5
0
/*
 * Bind a socket to a privileged IP port
 */
int
bindresvport_sa(int sd, struct sockaddr *sa)
{
	int old, error, af;
	struct sockaddr_storage myaddr;
	struct sockaddr_in *sin;
#ifdef INET6
	struct sockaddr_in6 *sin6;
#endif
	int proto, portrange, portlow;
	u_int16_t *portp;
	socklen_t salen;

	if (sa == NULL) {
		salen = sizeof(myaddr);
		sa = (struct sockaddr *)&myaddr;

		if (_getsockname(sd, sa, &salen) == -1)
			return -1;	/* errno is correctly set */

		af = sa->sa_family;
		memset(sa, 0, salen);
	} else
		af = sa->sa_family;

	switch (af) {
	case AF_INET:
		proto = IPPROTO_IP;
		portrange = IP_PORTRANGE;
		portlow = IP_PORTRANGE_LOW;
		sin = (struct sockaddr_in *)sa;
		salen = sizeof(struct sockaddr_in);
		portp = &sin->sin_port;
		break;
#ifdef INET6
	case AF_INET6:
		proto = IPPROTO_IPV6;
		portrange = IPV6_PORTRANGE;
		portlow = IPV6_PORTRANGE_LOW;
		sin6 = (struct sockaddr_in6 *)sa;
		salen = sizeof(struct sockaddr_in6);
		portp = &sin6->sin6_port;
		break;
#endif
	default:
		errno = EPFNOSUPPORT;
		return (-1);
	}
	sa->sa_family = af;
	sa->sa_len = salen;

	if (*portp == 0) {
		socklen_t oldlen = sizeof(old);

		error = _getsockopt(sd, proto, portrange, &old, &oldlen);
		if (error < 0)
			return (error);

		error = _setsockopt(sd, proto, portrange, &portlow,
		    sizeof(portlow));
		if (error < 0)
			return (error);
	}

	error = _bind(sd, sa, salen);

	if (*portp == 0) {
		int saved_errno = errno;

		if (error < 0) {
			if (_setsockopt(sd, proto, portrange, &old,
			    sizeof(old)) < 0)
				errno = saved_errno;
			return (error);
		}

		if (sa != (struct sockaddr *)&myaddr) {
			/* Hmm, what did the kernel assign? */
			if (_getsockname(sd, sa, &salen) < 0)
				errno = saved_errno;
			return (error);
		}
	}
	return (error);
}