Exemple #1
0
/*! @decl string query_address()
 *!
 *! Get the address and port of the local socket end-point.
 *!
 *! @returns
 *!   This function returns the address and port of a socket end-point
 *!   on the form @expr{"x.x.x.x port"@} (IPv4) or
 *!   @expr{"x:x:x:x:x:x:x:x port"@} (IPv6).
 *!
 *!   If there is some error querying or formatting the address,
 *!   @expr{0@} (zero) is returned and @[errno()] will return the
 *!   error code.
 *!
 *! @throws
 *!   An error is thrown if the socket isn't bound.
 */
static void socket_query_address(INT32 args)
{
  PIKE_SOCKADDR addr;
  int i;
  char buffer[496];
  ACCEPT_SIZE_T len;

  if(THIS->box.fd <0)
    Pike_error("Stdio.Port->query_address(): Socket not bound yet.\n");

  len=sizeof(addr);
  i=fd_getsockname(THIS->box.fd,(struct sockaddr *)&addr,&len);
  pop_n_elems(args);
  if(i < 0 || len < (int)sizeof(addr.ipv4))
  {
    THIS->my_errno=errno;
    push_int(0);
    return;
  }

#ifdef fd_inet_ntop
  if(!fd_inet_ntop(SOCKADDR_FAMILY(addr), SOCKADDR_IN_ADDR(addr),
		   buffer, sizeof(buffer)-20))
  {
    THIS->my_errno = errno;
    push_int(0);
    return;
  }
#else
  if(SOCKADDR_FAMILY(addr) == AF_INET)
  {
    char *q = inet_ntoa(*SOCKADDR_IN_ADDR(addr));
    strncpy(buffer,q,sizeof(buffer)-20);
    buffer[sizeof(buffer)-20]=0;
  }else{
#ifdef EAFNOSUPPORT
    THIS->my_errno = EAFNOSUPPORT;
#else
    THIS->my_errno = EINVAL;
#endif
    push_int(0);
    return;
  }
#endif
  sprintf(buffer+strlen(buffer)," %d",(int)(ntohs(addr.ipv4.sin_port)));

  push_text(buffer);
}
Exemple #2
0
static void push_log_entry(struct log_entry *le)
{
  struct object *o = clone_object( aap_log_object_program, 0 );
  struct log_object *lo = (struct log_object*)o->storage;
  lo->time = le->t;
  lo->sent_bytes = le->sent_bytes;
  lo->reply = le->reply;
  lo->received_bytes = le->received_bytes;
  lo->raw = make_shared_binary_string(le->raw.str, le->raw.len);
  lo->url = make_shared_binary_string(le->url.str, le->url.len);
  lo->method = make_shared_binary_string(le->method.str, le->method.len);
  lo->protocol = le->protocol;
  le->protocol->refs++;
#ifdef HAVE_INET_NTOP
  {
    char buffer[64];
    lo->from = make_shared_string( inet_ntop(SOCKADDR_FAMILY(le->from),
					     SOCKADDR_IN_ADDR(le->from),
					     buffer, sizeof(buffer)) );
  }
#else
  lo->from = make_shared_string( inet_ntoa(*SOCKADDR_IN_ADDR(le->from)) );
#endif
  push_object( o );
}
Exemple #3
0
static rc_vchar_t *
natt_create_hash(isakmp_index_t *index, struct sockaddr *addr, int use_spi_r)
{
	rc_vchar_t *hash;
	rc_vchar_t *buf;
	char *ptr;
	void *addr_ptr, *addr_port;
	size_t buf_size, addr_size;

	switch (SOCKADDR_FAMILY(addr)) {
	case AF_INET:
		addr_size = sizeof(struct in_addr);
		addr_ptr = &((struct sockaddr_in *)addr)->sin_addr;
		addr_port = &((struct sockaddr_in *)addr)->sin_port;
		break;

#ifdef INET6
	case AF_INET6:
		addr_size = sizeof(struct in6_addr);
		addr_ptr = &((struct sockaddr_in6 *)addr)->sin6_addr;
		addr_port = &((struct sockaddr_in6 *)addr)->sin6_port;
		break;
#endif

	default:
		plog(PLOG_PROTOERR, PLOGLOC, NULL,
		     "Unsupported address family %d\n", addr->sa_family);
		return NULL;
	}

	buf_size = 2 * sizeof(isakmp_cookie_t);
	buf_size += addr_size + 2;	/* address + port */

	if ((buf = rc_vmalloc(buf_size)) == NULL) {
		plog(PLOG_INTERR, PLOGLOC, NULL,
		     "failed to rc_vmalloc in natt_create_hash\n");
		return NULL;
	}

	ptr = buf->v;

	memcpy(ptr, &index->i_ck, sizeof(isakmp_cookie_t));
	ptr += sizeof(isakmp_cookie_t);

	if (use_spi_r) {
		memcpy(ptr, &index->r_ck, sizeof(isakmp_cookie_t));
	}
	ptr += sizeof(isakmp_cookie_t);

	memcpy(ptr, addr_ptr, addr_size);
	ptr += addr_size;

	memcpy(ptr, addr_port, 2);

	hash = eay_sha1_one(buf);
	rc_vfree(buf);

	return hash;
}
Exemple #4
0
static void
send_keepalive_msg(void)
{
    XdmcpHeader header;
    int socketfd = xdmcpSocket;

    header.version = XDM_PROTOCOL_VERSION;
    header.opcode = (CARD16) KEEPALIVE;
    header.length = 6;

    XdmcpWriteHeader(&buffer, &header);
    XdmcpWriteCARD16(&buffer, DisplayNumber);
    XdmcpWriteCARD32(&buffer, SessionID);

    state = XDM_AWAIT_ALIVE_RESPONSE;
#if defined(IPv6) && defined(AF_INET6)
    if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
        socketfd = xdmcpSocket6;
#endif
    XdmcpFlush(socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen);
}
Exemple #5
0
static void
send_manage_msg(void)
{
    XdmcpHeader header;
    int socketfd = xdmcpSocket;

    header.version = XDM_PROTOCOL_VERSION;
    header.opcode = (CARD16) MANAGE;
    header.length = 8 + DisplayClass.length;

    if (!XdmcpWriteHeader(&buffer, &header))
        return;
    XdmcpWriteCARD32(&buffer, SessionID);
    XdmcpWriteCARD16(&buffer, DisplayNumber);
    XdmcpWriteARRAY8(&buffer, &DisplayClass);
    state = XDM_AWAIT_MANAGE_RESPONSE;
#if defined(IPv6) && defined(AF_INET6)
    if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
        socketfd = xdmcpSocket6;
#endif
    XdmcpFlush(socketfd, &buffer, (XdmcpNetaddr) &req_sockaddr, req_socklen);
}
Exemple #6
0
void
XdmcpRegisterConnection(int type, const char *address, int addrlen)
{
    int i;
    CARD8 *newAddress;

    if (xdmcpGeneration != serverGeneration) {
        XdmcpDisposeARRAY16(&ConnectionTypes);
        XdmcpDisposeARRAYofARRAY8(&ConnectionAddresses);
        xdmcpGeneration = serverGeneration;
    }
    if (xdm_from != NULL) {     /* Only register the requested address */
        const void *regAddr = address;
        const void *fromAddr = NULL;
        int regAddrlen = addrlen;

        if (addrlen == sizeof(struct in_addr)) {
            if (SOCKADDR_FAMILY(FromAddress) == AF_INET) {
                fromAddr = &((struct sockaddr_in *) &FromAddress)->sin_addr;
            }
#if defined(IPv6) && defined(AF_INET6)
            else if ((SOCKADDR_FAMILY(FromAddress) == AF_INET6) &&
                     IN6_IS_ADDR_V4MAPPED(&
                                          ((struct sockaddr_in6 *)
                                           &FromAddress)->sin6_addr)) {
                fromAddr =
                    &((struct sockaddr_in6 *) &FromAddress)->sin6_addr.
                    s6_addr[12];
            }
#endif
        }
#if defined(IPv6) && defined(AF_INET6)
        else if (addrlen == sizeof(struct in6_addr)) {
            if (SOCKADDR_FAMILY(FromAddress) == AF_INET6) {
                fromAddr = &((struct sockaddr_in6 *) &FromAddress)->sin6_addr;
            }
            else if ((SOCKADDR_FAMILY(FromAddress) == AF_INET) &&
                     IN6_IS_ADDR_V4MAPPED((const struct in6_addr *) address)) {
                fromAddr = &((struct sockaddr_in *) &FromAddress)->sin_addr;
                regAddr =
                    &((struct sockaddr_in6 *) &address)->sin6_addr.s6_addr[12];
                regAddrlen = sizeof(struct in_addr);
            }
        }
#endif
        if (!fromAddr || memcmp(regAddr, fromAddr, regAddrlen) != 0) {
            return;
        }
    }
    if (ConnectionAddresses.length + 1 == 256)
        return;
    newAddress = malloc(addrlen * sizeof(CARD8));
    if (!newAddress)
        return;
    if (!XdmcpReallocARRAY16(&ConnectionTypes, ConnectionTypes.length + 1)) {
        free(newAddress);
        return;
    }
    if (!XdmcpReallocARRAYofARRAY8(&ConnectionAddresses,
                                   ConnectionAddresses.length + 1)) {
        free(newAddress);
        return;
    }
    ConnectionTypes.data[ConnectionTypes.length - 1] = (CARD16) type;
    for (i = 0; i < addrlen; i++)
        newAddress[i] = address[i];
    ConnectionAddresses.data[ConnectionAddresses.length - 1].data = newAddress;
    ConnectionAddresses.data[ConnectionAddresses.length - 1].length = addrlen;
}
Exemple #7
0
static void
send_request_msg(void)
{
    XdmcpHeader header;
    int length;
    int i;
    CARD16 XdmcpConnectionType;
    ARRAY8 authenticationData;
    int socketfd = xdmcpSocket;

    switch (SOCKADDR_FAMILY(ManagerAddress)) {
    case AF_INET:
        XdmcpConnectionType = FamilyInternet;
        break;
#if defined(IPv6) && defined(AF_INET6)
    case AF_INET6:
        XdmcpConnectionType = FamilyInternet6;
        break;
#endif
    default:
        XdmcpConnectionType = 0xffff;
        break;
    }

    header.version = XDM_PROTOCOL_VERSION;
    header.opcode = (CARD16) REQUEST;

    length = 2;                 /* display number */
    length += 1 + 2 * ConnectionTypes.length;   /* connection types */
    length += 1;                /* connection addresses */
    for (i = 0; i < ConnectionAddresses.length; i++)
        length += 2 + ConnectionAddresses.data[i].length;
    authenticationData.length = 0;
    authenticationData.data = 0;
    if (AuthenticationFuncs) {
        (*AuthenticationFuncs->Generator) (AuthenticationData,
                                           &authenticationData, REQUEST);
    }
    length += 2 + AuthenticationName->length;   /* authentication name */
    length += 2 + authenticationData.length;    /* authentication data */
    length += 1;                /* authorization names */
    for (i = 0; i < AuthorizationNames.length; i++)
        length += 2 + AuthorizationNames.data[i].length;
    length += 2 + ManufacturerDisplayID.length; /* display ID */
    header.length = length;

    if (!XdmcpWriteHeader(&buffer, &header)) {
        XdmcpDisposeARRAY8(&authenticationData);
        return;
    }
    XdmcpWriteCARD16(&buffer, DisplayNumber);
    XdmcpWriteCARD8(&buffer, ConnectionTypes.length);

    /* The connection array is send reordered, so that connections of   */
    /* the same address type as the XDMCP manager connection are send   */
    /* first. This works around a bug in xdm. [email protected]          */
    for (i = 0; i < (int) ConnectionTypes.length; i++)
        if (ConnectionTypes.data[i] == XdmcpConnectionType)
            XdmcpWriteCARD16(&buffer, ConnectionTypes.data[i]);
    for (i = 0; i < (int) ConnectionTypes.length; i++)
        if (ConnectionTypes.data[i] != XdmcpConnectionType)
            XdmcpWriteCARD16(&buffer, ConnectionTypes.data[i]);

    XdmcpWriteCARD8(&buffer, ConnectionAddresses.length);
    for (i = 0; i < (int) ConnectionAddresses.length; i++)
        if ((i < ConnectionTypes.length) &&
            (ConnectionTypes.data[i] == XdmcpConnectionType))
            XdmcpWriteARRAY8(&buffer, &ConnectionAddresses.data[i]);
    for (i = 0; i < (int) ConnectionAddresses.length; i++)
        if ((i >= ConnectionTypes.length) ||
            (ConnectionTypes.data[i] != XdmcpConnectionType))
            XdmcpWriteARRAY8(&buffer, &ConnectionAddresses.data[i]);

    XdmcpWriteARRAY8(&buffer, AuthenticationName);
    XdmcpWriteARRAY8(&buffer, &authenticationData);
    XdmcpDisposeARRAY8(&authenticationData);
    XdmcpWriteARRAYofARRAY8(&buffer, &AuthorizationNames);
    XdmcpWriteARRAY8(&buffer, &ManufacturerDisplayID);
#if defined(IPv6) && defined(AF_INET6)
    if (SOCKADDR_FAMILY(req_sockaddr) == AF_INET6)
        socketfd = xdmcpSocket6;
#endif
    if (XdmcpFlush(socketfd, &buffer,
                   (XdmcpNetaddr) &req_sockaddr, req_socklen))
        state = XDM_AWAIT_REQUEST_RESPONSE;
}
Exemple #8
0
static void
send_query_msg(void)
{
    XdmcpHeader header;
    Bool broadcast = FALSE;

#if defined(IPv6) && defined(AF_INET6)
    Bool multicast = FALSE;
#endif
    int i;
    int socketfd = xdmcpSocket;

    header.version = XDM_PROTOCOL_VERSION;
    switch (state) {
    case XDM_QUERY:
        header.opcode = (CARD16) QUERY;
        state = XDM_COLLECT_QUERY;
        break;
    case XDM_BROADCAST:
        header.opcode = (CARD16) BROADCAST_QUERY;
        state = XDM_COLLECT_BROADCAST_QUERY;
        broadcast = TRUE;
        break;
#if defined(IPv6) && defined(AF_INET6)
    case XDM_MULTICAST:
        header.opcode = (CARD16) BROADCAST_QUERY;
        state = XDM_COLLECT_MULTICAST_QUERY;
        multicast = TRUE;
        break;
#endif
    case XDM_INDIRECT:
        header.opcode = (CARD16) INDIRECT_QUERY;
        state = XDM_COLLECT_INDIRECT_QUERY;
        break;
    default:
        break;
    }
    header.length = 1;
    for (i = 0; i < AuthenticationNames.length; i++)
        header.length += 2 + AuthenticationNames.data[i].length;

    XdmcpWriteHeader(&buffer, &header);
    XdmcpWriteARRAYofARRAY8(&buffer, &AuthenticationNames);
    if (broadcast) {
        for (i = 0; i < NumBroadcastAddresses; i++)
            XdmcpFlush(xdmcpSocket, &buffer,
                       (XdmcpNetaddr) &BroadcastAddresses[i],
                       sizeof(struct sockaddr_in));
    }
#if defined(IPv6) && defined(AF_INET6)
    else if (multicast) {
        struct multicastinfo *mcl;
        struct addrinfo *ai;

        for (mcl = mcastlist; mcl != NULL; mcl = mcl->next) {
            for (ai = mcl->ai; ai != NULL; ai = ai->ai_next) {
                if (ai->ai_family == AF_INET) {
                    unsigned char hopflag = (unsigned char) mcl->hops;

                    socketfd = xdmcpSocket;
                    setsockopt(socketfd, IPPROTO_IP, IP_MULTICAST_TTL,
                               &hopflag, sizeof(hopflag));
                }
                else if (ai->ai_family == AF_INET6) {
                    int hopflag6 = mcl->hops;

                    socketfd = xdmcpSocket6;
                    setsockopt(socketfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
                               &hopflag6, sizeof(hopflag6));
                }
                else {
                    continue;
                }
                XdmcpFlush(socketfd, &buffer,
                           (XdmcpNetaddr) ai->ai_addr, ai->ai_addrlen);
                break;
            }
        }
    }
#endif
    else {
#if defined(IPv6) && defined(AF_INET6)
        if (SOCKADDR_FAMILY(ManagerAddress) == AF_INET6)
            socketfd = xdmcpSocket6;
#endif
        XdmcpFlush(socketfd, &buffer, (XdmcpNetaddr) &ManagerAddress,
                   ManagerAddressLen);
    }
}
Exemple #9
0
/* send packet, with fixing src/dst address pair. */
int
sendfromto(int s, const void *buf, size_t buflen, 
	   struct sockaddr *src, struct sockaddr *dst, int cnt)
{
	struct sockaddr_storage ss;
	socklen_t sslen;
	int len = 0, i;
	extern struct rcf_interface *rcf_interface_head;

	if (cnt <= 0) {
		TRACE((PLOGLOC, "cnt: %d\n", cnt));
		return 0;
	}

	if (src->sa_family != dst->sa_family) {
		plog(PLOG_INTERR, PLOGLOC, NULL, "address family mismatch\n");
		return -1;
	}

	memset(&ss, 0, sizeof(ss));
	sslen = sizeof(ss);
	if (getsockname(s, (struct sockaddr *)&ss, &sslen) < 0) {
		plog(PLOG_INTERR, PLOGLOC, NULL,
		     "getsockname (%s)\n", strerror(errno));
		return -1;
	}

	plog(PLOG_DEBUG, PLOGLOC, NULL,
	     "sockname %s\n", rcs_sa2str((struct sockaddr *)&ss));
	plog(PLOG_DEBUG, PLOGLOC, NULL,
	     "send packet from %s\n", rcs_sa2str(src));
	plog(PLOG_DEBUG, PLOGLOC, NULL, "send packet to %s\n", rcs_sa2str(dst));

	if (src->sa_family != SOCKADDR_FAMILY(&ss)) {
		plog(PLOG_INTERR, PLOGLOC, NULL, "address family mismatch\n");
		return -1;
	}

	switch (src->sa_family) {
#if defined(INET6) && defined(ADVAPI) && !defined(IPV6_INRIA_VERSION)
	case AF_INET6:
		{
			struct msghdr m;
			struct cmsghdr *cm;
			struct iovec iov[2];
			unsigned char cmsgbuf[256];
			struct in6_pktinfo *pi;
			int ifindex;
			struct sockaddr_in6 src6, dst6;

			memcpy(&src6, src, sizeof(src6));
			memcpy(&dst6, dst, sizeof(dst6));

			/* XXX take care of other cases, such as site-local */
			ifindex = 0;
			if (IN6_IS_ADDR_LINKLOCAL(&src6.sin6_addr)
			    || IN6_IS_ADDR_MULTICAST(&src6.sin6_addr)) {
				ifindex = src6.sin6_scope_id;	/*??? */
			}

			/* XXX some sanity check on dst6.sin6_scope_id */

			/* flowinfo for IKE?  mmm, maybe useful but for now make it 0 */
			src6.sin6_flowinfo = dst6.sin6_flowinfo = 0;

			memset(&m, 0, sizeof(m));
			m.msg_name = (caddr_t)&dst6;
			m.msg_namelen = sizeof(dst6);
			iov[0].iov_base = (char *)buf;
			iov[0].iov_len = buflen;
			m.msg_iov = iov;
			m.msg_iovlen = 1;

			memset(cmsgbuf, 0, sizeof(cmsgbuf));
			cm = (struct cmsghdr *)cmsgbuf;
			m.msg_control = (caddr_t)cm;
			m.msg_controllen =
				CMSG_SPACE(sizeof(struct in6_pktinfo));

			cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
			cm->cmsg_level = IPPROTO_IPV6;
			cm->cmsg_type = IPV6_PKTINFO;
			pi = (struct in6_pktinfo *)CMSG_DATA(cm);
			memcpy(&pi->ipi6_addr, &src6.sin6_addr,
			       sizeof(src6.sin6_addr));
			pi->ipi6_ifindex = ifindex;

			plog(PLOG_DEBUG, PLOGLOC, NULL,
			     "src6 %s %d\n",
			     rcs_sa2str((struct sockaddr *)&src6),
			     src6.sin6_scope_id);
			plog(PLOG_DEBUG, PLOGLOC, NULL,
			     "dst6 %s %d\n",
			     rcs_sa2str((struct sockaddr *)&dst6),
			     dst6.sin6_scope_id);

			for (i = 0; i < cnt; i++) {
				len = sendmsg(s, &m, 0 /*MSG_DONTROUTE */ );
				if (len < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "sendmsg (%s)\n", strerror(errno));
					return -1;
				}
				plog(PLOG_DEBUG, PLOGLOC, NULL,
				     "%d times of %d bytes message will be sent "
				     "to %s\n", i + 1, len, rcs_sa2str(dst));
			}
			plogdump(PLOG_DEBUG, PLOGLOC, 0, (char *)buf, buflen);

			return len;
		}
#endif
	default:
		{
			int needclose = 0;
			int sendsock;

			if (rcs_cmpsa((struct sockaddr *)&ss, src) == 0) {
				sendsock = s;
				needclose = 0;
			} else {
				int yes = 1;
				/*
				 * Use newly opened socket for sending packets.
				 * NOTE: this is unsafe, because if the peer is quick enough
				 * the packet from the peer may be queued into sendsock.
				 * Better approach is to prepare bind'ed udp sockets for
				 * each of the interface addresses.
				 */
				sendsock =
					socket(src->sa_family, SOCK_DGRAM, 0);
				if (sendsock < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "socket (%s)\n", strerror(errno));
					return -1;
				}
#ifdef SO_REUSEPORT
				if (setsockopt(sendsock, SOL_SOCKET, SO_REUSEPORT,
				     (void *)&yes, sizeof(yes)) < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "setsockopt (%s)\n",
					     strerror(errno));
					close(sendsock);
					return -1;
				}
#else
#ifdef SO_REUSEADDR
				if (setsockopt(sendsock, SOL_SOCKET, SO_REUSEADDR,
				     (void *)&yes, sizeof(yes)) < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "setsockopt (%s)\n",
					     strerror(errno));
					close(sendsock);
					return -1;
				}
#else
#error
#endif
#endif

#ifdef IPV6_USE_MIN_MTU
				if (src->sa_family == AF_INET6 &&
				    setsockopt(sendsock, IPPROTO_IPV6,
					       IPV6_USE_MIN_MTU, (void *)&yes,
					       sizeof(yes)) < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "setsockopt (%s)\n",
					     strerror(errno));
					close(sendsock);
					return -1;
				}
#endif
				if (rcf_interface_head->application_bypass
				    != RCT_BOOL_OFF &&
				    setsockopt_bypass(sendsock, src->sa_family)
				    < 0) {
					close(sendsock);
					return -1;
				}

				if (bind
				    (sendsock, (struct sockaddr *)src,
				     SOCKADDR_LEN(src)) < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "bind 1 (%s)\n", strerror(errno));
					close(sendsock);
					return -1;
				}
				needclose = 1;
			}

			for (i = 0; i < cnt; i++) {
#ifdef DEBUG
				extern uint32_t debug_send;
				static int send_count = 0;

				if (debug_send & (1 << (send_count++ % 32))) {
					/* simulate a network packet drop */
					TRACE((PLOGLOC, "debug_send %d drop\n", send_count));
					len = buflen;
				} else
#endif
					len = sendto(sendsock, buf, buflen, 0,
						     dst, SOCKADDR_LEN(dst));
				if (len < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "sendto (%s)\n", strerror(errno));
					if (needclose)
						close(sendsock);
					return len;
				}
				plog(PLOG_DEBUG, PLOGLOC, NULL,
				     "%d times of %d bytes message will be sent "
				     "to %s\n", i + 1, len, rcs_sa2str(dst));
			}
			plogdump(PLOG_DEBUG, PLOGLOC, 0, (char *)buf, buflen);

			if (needclose)
				close(sendsock);

			return len;
		}
	}
}
Exemple #10
0
/*
 * Receive packet, with src/dst information.  It is assumed that necessary
 * setsockopt() have already performed on socket.
 */
int
recvfromto(int s, void *buf, size_t buflen, int flags, 
	   struct sockaddr *from, int *fromlen, struct sockaddr *to, int *tolen)
{
	int otolen;
	int len;
	socklen_t sslen;
	struct sockaddr_storage ss;
	struct msghdr m;
	struct cmsghdr *cm;
	struct iovec iov[2];
	unsigned char cmsgbuf[256];
#if defined(INET6) && defined(ADVAPI)
	struct in6_pktinfo *pi;
#endif	 /*ADVAPI*/
#ifdef INET6
	struct sockaddr_in6 *sin6;
#endif

	sslen = sizeof(ss);
	if (getsockname(s, (struct sockaddr *)&ss, &sslen) < 0) {
		plog(PLOG_INTERR, PLOGLOC, NULL,
		     "getsockname (%s)\n", strerror(errno));
		return -1;
	}
#if 1
	/* quick hack */
	memcpy(to, &ss, sslen < *tolen ? sslen : *tolen);
#endif

	m.msg_name = (caddr_t)from;
	m.msg_namelen = *fromlen;
	iov[0].iov_base = (caddr_t)buf;
	iov[0].iov_len = buflen;
	m.msg_iov = iov;
	m.msg_iovlen = 1;
	memset(cmsgbuf, 0, sizeof(cmsgbuf));
	cm = (struct cmsghdr *)cmsgbuf;
	m.msg_control = (caddr_t)cm;
	m.msg_controllen = sizeof(cmsgbuf);
	if ((len = recvmsg(s, &m, flags)) < 0) {
		plog(PLOG_INTERR, PLOGLOC, NULL,
		     "recvmsg (%s)\n", strerror(errno));
		return -1;
	}
	*fromlen = m.msg_namelen;

	otolen = *tolen;
	*tolen = 0;
	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
	     m.msg_controllen != 0 && cm;
	     cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
#if 1
		plog(PLOG_DEBUG, PLOGLOC, NULL,
		     "cmsg %d %d\n", cm->cmsg_level, cm->cmsg_type);
#endif
#if defined(INET6) && defined(ADVAPI)
		if (SOCKADDR_FAMILY(&ss) == AF_INET6
		    && cm->cmsg_level == IPPROTO_IPV6
		    && cm->cmsg_type == IPV6_PKTINFO
		    && otolen >= (int)sizeof(*sin6)) {
			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
			*tolen = sizeof(*sin6);
			sin6 = (struct sockaddr_in6 *)to;
			memset(sin6, 0, sizeof(*sin6));
			sin6->sin6_family = AF_INET6;
			SET_SOCKADDR_LEN(sin6, sizeof(*sin6));
			memcpy(&sin6->sin6_addr, &pi->ipi6_addr,
			       sizeof(sin6->sin6_addr));
			/* XXX other cases, such as site-local? */
			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
				sin6->sin6_scope_id = pi->ipi6_ifindex;
			else
				sin6->sin6_scope_id = 0;
			sin6->sin6_port =
				((struct sockaddr_in6 *)&ss)->sin6_port;
			otolen = -1;	/* "to" already set */
			continue;
		}
#endif
#if defined(INET6) && defined(IPV6_RECVDSTADDR)
		if (ss.ss_family == AF_INET6
		    && cm->cmsg_level == IPPROTO_IPV6
		    && cm->cmsg_type == IPV6_RECVDSTADDR
		    && otolen >= sizeof(*sin6)) {
			*tolen = sizeof(*sin6);
			sin6 = (struct sockaddr_in6 *)to;
			memset(sin6, 0, sizeof(*sin6));
			sin6->sin6_family = AF_INET6;
			sin6->sin6_len = sizeof(*sin6);
			memcpy(&sin6->sin6_addr, CMSG_DATA(cm),
			       sizeof(sin6->sin6_addr));
			sin6->sin6_port =
				((struct sockaddr_in6 *)&ss)->sin6_port;
			otolen = -1;	/* "to" already set */
			continue;
		}
#endif
#ifdef IP_RECVDSTADDR
		if (ss.ss_family == AF_INET
		    && cm->cmsg_level == IPPROTO_IP
		    && cm->cmsg_type == IP_RECVDSTADDR
		    && otolen >= (int)sizeof(struct sockaddr_in)) {
			struct sockaddr_in *sin;

			*tolen = sizeof(*sin);
			sin = (struct sockaddr_in *)to;
			memset(sin, 0, sizeof(*sin));
			sin->sin_family = AF_INET;
			sin->sin_len = sizeof(*sin);
			memcpy(&sin->sin_addr, CMSG_DATA(cm),
			       sizeof(sin->sin_addr));
			sin->sin_port = ((struct sockaddr_in *)&ss)->sin_port;
			otolen = -1;	/* "to" already set */
			continue;
		}
#else
#if defined(IP_PKTINFO)

#else
#error
#endif
#endif
	}

	return len;
}
Exemple #11
0
/*! @decl int bind(int|string port, void|function accept_callback, @
 *!                void|string ip, void|string reuse_port)
 *!
 *! Opens a socket and binds it to port number on the local machine.
 *! If the second argument is present, the socket is set to
 *! nonblocking and the callback funcition is called whenever
 *! something connects to it. The callback will receive the id for
 *! this port as argument and should typically call @[accept] to
 *! establish a connection.
 *!
 *! If the optional argument @[ip] is given, @[bind] will try to bind
 *! to an interface with that host name or IP number. Omitting this
 *! will bind to all available IPv4 addresses; specifying "::" will
 *! bind to all IPv4 and IPv6 addresses.
 *!
 *! If the OS supports TCP_FASTOPEN it is enabled automatically.
 *!
 *! If the OS supports SO_REUSEPORT it is enabled if the fourth argument is true.
 *!
 *! @returns
 *!   1 is returned on success, zero on failure. @[errno] provides
 *!   further details about the error in the latter case.
 *!
 *! @seealso
 *!   @[accept], @[set_id]
 */
static void port_bind(INT32 args)
{
  struct port *p = THIS;
  PIKE_SOCKADDR addr;
  int addr_len,fd,tmp;

  do_close(p);

  if(args < 1)
    SIMPLE_WRONG_NUM_ARGS_ERROR("bind", 1);

  if(TYPEOF(Pike_sp[-args]) != PIKE_T_INT &&
     (TYPEOF(Pike_sp[-args]) != PIKE_T_STRING ||
      Pike_sp[-args].u.string->size_shift))
    SIMPLE_ARG_TYPE_ERROR("bind", 1, "int|string(8bit)");

  addr_len = get_inet_addr(&addr,
                           (args > 2 && TYPEOF(Pike_sp[2-args])==PIKE_T_STRING?
                            Pike_sp[2-args].u.string->str : NULL),
                           (TYPEOF(Pike_sp[-args]) == PIKE_T_STRING?
                            Pike_sp[-args].u.string->str : NULL),
			   (TYPEOF(Pike_sp[-args]) == PIKE_T_INT?
			    Pike_sp[-args].u.integer : -1), 0);
  INVALIDATE_CURRENT_TIME();

  fd=fd_socket(SOCKADDR_FAMILY(addr), SOCK_STREAM, 0);

  if(fd < 0)
  {
    p->my_errno=errno;
    pop_n_elems(args);
    push_int(0);
    return;
  }
#ifdef SO_REUSEPORT
  if( args > 3 && Pike_sp[3-args].u.integer )
  {
    /* FreeBSD 7.x wants this to reuse portnumbers.
     * Linux 2.6.x seems to have reserved a slot for the option, but not
     * enabled it. Survive libc's with the option on kernels without.
     *
     * The emulated Linux runtime on MS Windows 10 fails this with EINVAL.
     */
    int o=1;
    if((fd_setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&o, sizeof(int)) < 0)
#ifdef ENOPROTOOPT
       && (errno != ENOPROTOOPT)
#endif
#ifdef EINVAL
       && (errno != EINVAL)
#endif
#ifdef WSAENOPROTOOPT
       && (errno != WSAENOPROTOOPT)
#endif
       ){
      p->my_errno=errno;
      while (fd_close(fd) && errno == EINTR) {}
      errno = p->my_errno;
      pop_n_elems(args);
      push_int(0);
      return;
    }
  }
#endif
#ifndef __NT__
  {
    int o=1;
    if(fd_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(int)) < 0)
    {
      p->my_errno=errno;
      while (fd_close(fd) && errno == EINTR) {}
      errno = p->my_errno;
      pop_n_elems(args);
      push_int(0);
      return;
    }
  }
#endif

#if defined(IPV6_V6ONLY) && defined(IPPROTO_IPV6)
  if (SOCKADDR_FAMILY(addr) == AF_INET6) {
    /* Attempt to enable dual-stack (ie mapped IPv4 adresses).
     * Needed on WIN32.
     * cf http://msdn.microsoft.com/en-us/library/windows/desktop/bb513665(v=vs.85).aspx
     */
    int o = 0;
    fd_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&o, sizeof(int));
  }
#endif

  my_set_close_on_exec(fd,1);

  THREADS_ALLOW_UID();
  if( !(tmp=fd_bind(fd, (struct sockaddr *)&addr, addr_len) < 0) )
#ifdef TCP_FASTOPEN
      tmp = 256,
      setsockopt(fd,SOL_TCP, TCP_FASTOPEN, &tmp, sizeof(tmp)),
#endif
      (tmp =  fd_listen(fd, 16384) < 0);
  THREADS_DISALLOW_UID();

  if(!Pike_fp->current_object->prog)
  {
    if (fd >= 0)
      while (fd_close(fd) && errno == EINTR) {}
    Pike_error("Object destructed in Stdio.Port->bind()\n");
  }

  if(tmp)
  {
    p->my_errno=errno;
    while (fd_close(fd) && errno == EINTR) {}
    errno = p->my_errno;
    pop_n_elems(args);
    push_int(0);
    return;
  }

  change_fd_for_box (&p->box, fd);
  if(args > 1) assign_accept_cb (p, Pike_sp+1-args);
  p->my_errno=0;
  pop_n_elems(args);
  push_int(1);
}
Exemple #12
0
void f_aap_log_as_commonlog_to_file(INT32 args)
{
  struct log_entry *le;
  struct log *l = LTHIS->log;
  int n = 0;
  int mfd, ot=0;
  struct object *f;
  struct tm tm;
  FILE *foo;
  static const char *month[] = {
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Oct", "Sep", "Nov", "Dec",
  };

  get_all_args("log_as_commonlog_to_file", args, "%o", &f);
  f->refs++;

  pop_n_elems(args);
  apply(f, "query_fd", 0);
  mfd = fd_dup(sp[-1].u.integer);
  if(mfd < 1)Pike_error("Bad fileobject to ->log_as_commonlog_to_file\n");
  pop_stack();

  foo = fdopen( mfd, "w" );
  if(!foo)
    Pike_error("Bad fileobject to ->log_as_commonlog_to_file\n");

  THREADS_ALLOW();

  mt_lock( &l->log_lock );
  le = l->log_head; 
  l->log_head = l->log_tail = 0;
  mt_unlock( &l->log_lock );

  while(le)
  {
    int i;
    struct tm *tm_p;
    struct log_entry *l = le->next;
    /* remotehost rfc931 authuser [date] "request" status bytes */
    if(le->t != ot)
    {
      time_t t = (time_t)le->t;
#ifdef HAVE_GMTIME_R
      gmtime_r( &t, &tm );
#else
#ifdef HAVE_GMTIME
      tm_p = gmtime( &t ); /* This will break if two threads run
			    gmtime() at once. */

#else
#ifdef HAVE_LOCALTIME
      tm_p = localtime( &t ); /* This will break if two threads run
			       localtime() at once. */
#endif
#endif
      if (tm_p) tm = *tm_p;
#endif
      ot = le->t;
    }

    /* date format:  [03/Feb/1998:23:08:20 +0000]  */

    /* GET [URL] HTTP/1.0 */
    for(i=13; i<le->raw.len; i++)
      if(le->raw.str[i] == '\r')
      {
	le->raw.str[i] = 0;
	break;
      }

#ifdef HAVE_INET_NTOP
    if(SOCKADDR_FAMILY(le->from) != AF_INET) {
      char buffer[64];
      fprintf(foo,
      "%s - %s [%02d/%s/%d:%02d:%02d:%02d +0000] \"%s\" %d %ld\n",
	      inet_ntop(SOCKADDR_FAMILY(le->from), SOCKADDR_IN_ADDR(le->from),
			buffer, sizeof(buffer)), /* hostname */
	      "-",                          /* remote-user */
	      tm.tm_mday, month[tm.tm_mon], tm.tm_year+1900,
	      tm.tm_hour, tm.tm_min, tm.tm_sec, /* date */
	      le->raw.str, /* request line */
	      le->reply, /* reply code */
	      DO_NOT_WARN((long)le->sent_bytes)); /* bytes transfered */
    } else
#endif /* HAVE_INET_NTOP */
    fprintf(foo,
    "%d.%d.%d.%d - %s [%02d/%s/%d:%02d:%02d:%02d +0000] \"%s\" %d %ld\n",
	    ((unsigned char *)&le->from.ipv4.sin_addr)[ 0 ],
	    ((unsigned char *)&le->from.ipv4.sin_addr)[ 1 ],
	    ((unsigned char *)&le->from.ipv4.sin_addr)[ 2 ],
	    ((unsigned char *)&le->from.ipv4.sin_addr)[ 3 ], /* hostname */
	    "-",                          /* remote-user */
	    tm.tm_mday, month[tm.tm_mon], tm.tm_year+1900,
	    tm.tm_hour, tm.tm_min, tm.tm_sec, /* date */
	    le->raw.str, /* request line */
	    le->reply, /* reply code */
	    DO_NOT_WARN((long)le->sent_bytes)); /* bytes transfered */
    free_log_entry( le );
    n++;
    le = l;
  }
  fclose(foo);
  fd_close(mfd);
  THREADS_DISALLOW();
  push_int(n);
}