Exemple #1
0
/* called within retry/fork loop, before connect() */
int
_xioopen_socks4_connect0(struct single *xfd,
                         const char *hostname,	/* socks target host */
                         int socks4a,
                         struct socks4 *sockhead,
                         ssize_t *headlen,		/* get available space,
							   return used length*/
                         int level) {
    int result;

    if (!socks4a) {
        union sockaddr_union sau;
        socklen_t saulen = sizeof(sau);

        if ((result = xiogetaddrinfo(hostname, NULL,
                                     PF_INET, SOCK_STREAM, IPPROTO_TCP,
                                     &sau, &saulen,
                                     xfd->para.socket.ip.res_opts[1],
                                     xfd->para.socket.ip.res_opts[0]))
                != STAT_OK) {
            return result;	/*! STAT_RETRY? */
        }
        memcpy(&sockhead->dest, &sau.ip4.sin_addr, 4);
    }
#if WITH_SOCKS4A
    else {
        /*! noresolve */
        sockhead->dest = htonl(0x00000001);	/* three bytes zero */
    }
#endif /* WITH_SOCKS4A */
#if WITH_SOCKS4A
    if (socks4a) {
        /* SOCKS4A requires us to append the host name to resolve
           after the user name's trailing 0 byte.  */
        char* insert_position = (char*) sockhead + *headlen;

        insert_position[0] = '\0';
        strncat(insert_position, hostname, BUFF_LEN-*headlen-1);
        ((char *)sockhead)[BUFF_LEN-1] = 0;
        *headlen += strlen(hostname) + 1;
        if (*headlen > BUFF_LEN) {
            *headlen = BUFF_LEN;
        }
    }
#endif /* WITH_SOCKS4A */
    return STAT_OK;
}
Exemple #2
0
/*
   applies and consumes the following options:
   OPT_PROTOCOL_FAMILY, OPT_BIND
 */
int _xioopen_ipapp_listen_prepare(struct opt *opts, struct opt **opts0,
				   const char *portname, int *pf, int ipproto,
				  unsigned long res_opts0,
				  unsigned long res_opts1,
				   union sockaddr_union *us, socklen_t *uslen,
				   int socktype) {
   char *bindname = NULL;
   int result;

   retropt_socket_pf(opts, pf);

   retropt_string(opts, OPT_BIND, &bindname);
   if ((result =
	xiogetaddrinfo(bindname, portname, *pf, socktype, ipproto,
		       (union sockaddr_union *)us, uslen,
		       res_opts0, res_opts1))
       != STAT_OK) {
      /*! STAT_RETRY? */
      return result;
   }

   *opts0 = copyopts(opts, GROUP_ALL);
   return STAT_OK;
}
Exemple #3
0
/* returns STAT_OK on success or some other value on failure
   applies and consumes the following options:
   PH_EARLY
   OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT
 */
int
   _xioopen_ipapp_prepare(struct opt *opts, struct opt **opts0,
			   const char *hostname,
			   const char *portname,
			   int *pf,
			   int protocol,
			   unsigned long res_opts0, unsigned long res_opts1,
			   union sockaddr_union *them, socklen_t *themlen,
			   union sockaddr_union *us, socklen_t *uslen,
			   bool *needbind, bool *lowport,
			   int socktype) {
   uint16_t port;
   char infobuff[256];
   int result;

   retropt_socket_pf(opts, pf);

   if ((result =
	xiogetaddrinfo(hostname, portname,
		       *pf, socktype, protocol,
		       (union sockaddr_union *)them, themlen,
		       res_opts0, res_opts1
		       ))
       != STAT_OK) {
      return STAT_NORETRY;	/*! STAT_RETRYLATER? */
   }
   if (*pf == PF_UNSPEC) {
      *pf = them->soa.sa_family;
   }

   applyopts(-1, opts, PH_EARLY);

   /* 3 means: IP address AND port accepted */
   if (retropt_bind(opts, *pf, socktype, protocol, (struct sockaddr *)us, uslen, 3,
		    res_opts0, res_opts1)
       != STAT_NOACTION) {
      *needbind = true;
   } else {
      switch (*pf) {
#if WITH_IP4
      case PF_INET:  socket_in_init(&us->ip4);  *uslen = sizeof(us->ip4); break;
#endif /* WITH_IP4 */
#if WITH_IP6
      case PF_INET6: socket_in6_init(&us->ip6); *uslen = sizeof(us->ip6); break;
#endif /* WITH_IP6 */
      }
   }

   if (retropt_2bytes(opts, OPT_SOURCEPORT, &port) >= 0) {
      switch (*pf) {
#if WITH_IP4
      case PF_INET:  us->ip4.sin_port = htons(port); break;
#endif /* WITH_IP4 */
#if WITH_IP6
      case PF_INET6: us->ip6.sin6_port = htons(port); break;
#endif /* WITH_IP6 */
      default: Error("unsupported protocol family");
      }
      *needbind = true;
   }

   retropt_bool(opts, OPT_LOWPORT, lowport);

   *opts0 = copyopts(opts, GROUP_ALL);

   Notice1("opening connection to %s",
	   sockaddr_info((struct sockaddr *)them, *themlen, infobuff, sizeof(infobuff)));
   return STAT_OK;
}
Exemple #4
0
static
int xioopen_udp_recv(int argc, const char *argv[], struct opt *opts,
		     int xioflags, xiofile_t *xfd, unsigned groups,
		     int pf, int socktype, int ipproto) {
   union sockaddr_union us;
   socklen_t uslen = sizeof(us);
   char *rangename;
   int result;

   if (argc != 2) {
      Error2("%s: wrong number of parameters (%d instead of 1)",
	     argv[0], argc-1);
      return STAT_NORETRY;
   }

   retropt_socket_pf(opts, &pf);
   if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6
      pf = xioopts.default_ip=='6'?PF_INET6:PF_INET;
#elif WITH_IP6
      pf = PF_INET6;
#else
      pf = PF_INET;
#endif
   }

   if ((result =
	xiogetaddrinfo(NULL, argv[1], pf, socktype, ipproto,
		       &us, &uslen, xfd->stream.para.socket.ip.res_opts[0],
		       xfd->stream.para.socket.ip.res_opts[1]))
       != STAT_OK) {
      return result;
   }
   if (pf == PF_UNSPEC) {
      pf = us.soa.sa_family;
   }

#if 1
   {
      union sockaddr_union la;
      socklen_t lalen = sizeof(la);
     
      if (retropt_bind(opts, pf, socktype, ipproto,
		       &xfd->stream.para.socket.la.soa, &lalen, 1,
		       xfd->stream.para.socket.ip.res_opts[0],
		       xfd->stream.para.socket.ip.res_opts[1])
	  != STAT_NOACTION) {
	 switch (pf) {
#if WITH_IP4
	 case PF_INET:
	    us.ip4.sin_addr  = xfd->stream.para.socket.la.ip4.sin_addr;  break;
#endif
#if WITH_IP6
	 case PF_INET6:
	    us.ip6.sin6_addr = xfd->stream.para.socket.la.ip6.sin6_addr; break;
#endif
	 }
      } else {
	 xfd->stream.para.socket.la.soa.sa_family = pf;
      }
   }
#endif

#if WITH_IP4 /*|| WITH_IP6*/
   if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
      if (xioparserange(rangename, pf, &xfd->stream.para.socket.range) < 0) {
	 return STAT_NORETRY;
      }
      xfd->stream.para.socket.dorange = true;
   }
#endif

#if WITH_LIBWRAP
   xio_retropt_tcpwrap(&xfd->stream, opts);
#endif /* WITH_LIBWRAP */

   if (retropt_ushort(opts, OPT_SOURCEPORT,
		      &xfd->stream.para.socket.ip.sourceport)
       >= 0) {
      xfd->stream.para.socket.ip.dosourceport = true;
   }
   retropt_bool(opts, OPT_LOWPORT, &xfd->stream.para.socket.ip.lowport);

   xfd->stream.dtype = XIODATA_RECV;
   if ((result = _xioopen_dgram_recv(&xfd->stream, xioflags, &us.soa, uslen,
				     opts, pf, socktype, ipproto, E_ERROR))
       != STAT_OK) {
      return result;
   }
   _xio_openlate(&xfd->stream, opts);
   return result;
}
Exemple #5
0
static
int xioopen_udp_recvfrom(int argc, const char *argv[], struct opt *opts,
		     int xioflags, xiofile_t *xfd, unsigned groups,
		     int pf, int socktype, int ipproto) {
   union sockaddr_union us;
   socklen_t uslen = sizeof(us);
   bool needbind = false;
   int result;

   if (argc != 2) {
      Error2("%s: wrong number of parameters (%d instead of 1)",
	     argv[0], argc-1);
      return STAT_NORETRY;
   }

   xfd->stream.howtoend = END_NONE;
   retropt_socket_pf(opts, &pf);
   if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6
      pf = xioopts.default_ip=='6'?PF_INET6:PF_INET;
#elif WITH_IP6
      pf = PF_INET6;
#else
      pf = PF_INET;
#endif
   }

   if ((result =
	xiogetaddrinfo(NULL, argv[1], pf, socktype, ipproto,
		       &us, &uslen, xfd->stream.para.socket.ip.res_opts[0],
		       xfd->stream.para.socket.ip.res_opts[1]))
       != STAT_OK) {
      return result;
   }
   if (pf == PF_UNSPEC) {
      pf = us.soa.sa_family;
   }

   {
      union sockaddr_union la;
      socklen_t lalen = sizeof(la);
     
      if (retropt_bind(opts, pf, socktype, ipproto, &la.soa, &lalen, 1,
		       xfd->stream.para.socket.ip.res_opts[0],
		       xfd->stream.para.socket.ip.res_opts[1])
	  != STAT_NOACTION) {
	 switch (pf) {
#if WITH_IP4
	 case PF_INET:  us.ip4.sin_addr  = la.ip4.sin_addr;  break;
#endif
#if WITH_IP6
	 case PF_INET6: us.ip6.sin6_addr = la.ip6.sin6_addr; break;
#endif
	 }
	 needbind = true;
      }
   }

   if (retropt_ushort(opts, OPT_SOURCEPORT, &xfd->stream.para.socket.ip.sourceport) >= 0) {
      xfd->stream.para.socket.ip.dosourceport = true;
   }
   retropt_bool(opts, OPT_LOWPORT, &xfd->stream.para.socket.ip.lowport);

   xfd->stream.dtype = XIODATA_RECVFROM_ONE;
   if ((result =
	_xioopen_dgram_recvfrom(&xfd->stream, xioflags, &us.soa, uslen,
				opts, pf, socktype, ipproto, E_ERROR))
       != STAT_OK) {
      return result;
   }
   _xio_openlate(&xfd->stream, opts);
   return STAT_OK;
}
Exemple #6
0
/*
   applies and consumes the following option:
   PH_INIT, PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
   OFUNC_OFFSET
   OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
 */
static
int _xioopen_udp_sendto(const char *hostname, const char *servname,
			struct opt *opts,
		     int xioflags, xiofile_t *xxfd, unsigned groups,
		     int pf, int socktype, int ipproto) {
   xiosingle_t *xfd = &xxfd->stream;
   union sockaddr_union us;
   socklen_t uslen;
   int feats = 3;	/* option bind supports address and port */
   bool needbind = false;
   int result;

   xfd->howtoend = END_SHUTDOWN;

   /* ...res_opts[] */
   if (applyopts_single(xfd, opts, PH_INIT) < 0)  return -1;
   applyopts(-1, opts, PH_INIT);

   xfd->salen = sizeof(xfd->peersa);
   if ((result =
	xiogetaddrinfo(hostname, servname, pf, socktype, ipproto,
		       &xfd->peersa, &xfd->salen,
		       xfd->para.socket.ip.res_opts[0],
		       xfd->para.socket.ip.res_opts[1]))
       != STAT_OK) {
      return result;
   }
   if (pf == PF_UNSPEC) {
      pf = xfd->peersa.soa.sa_family;
   }
   uslen = socket_init(pf, &us);
   if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, feats,
		    xfd->para.socket.ip.res_opts[0],
		    xfd->para.socket.ip.res_opts[1])
       != STAT_NOACTION) {
      needbind = true;
   }

   if (retropt_ushort(opts, OPT_SOURCEPORT,
		      &xfd->para.socket.ip.sourceport) >= 0) {
      switch (pf) {
#if WITH_IP4
      case PF_INET:
	 us.ip4.sin_port = htons(xfd->para.socket.ip.sourceport);
	 break;
#endif
#if WITH_IP6
      case PF_INET6:
	 us.ip6.sin6_port = htons(xfd->para.socket.ip.sourceport);
	 break;
#endif
      }
      needbind = true;
   }

   retropt_bool(opts, OPT_LOWPORT, &xfd->para.socket.ip.lowport);
   if (xfd->para.socket.ip.lowport) {
      switch (pf) {
#if WITH_IP4
      case PF_INET:
	 /*!!! this is buggy */
	 us.ip4.sin_port = htons(xfd->para.socket.ip.lowport); break;
#endif
#if WITH_IP6
      case PF_INET6: 
	 /*!!! this is buggy */
	 us.ip6.sin6_port = htons(xfd->para.socket.ip.lowport); break;
#endif
      }
      needbind = true;
   }

   xfd->dtype = XIODATA_RECVFROM;
   return _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
			      opts, xioflags, xfd, groups,
			      pf, socktype, ipproto);
}
Exemple #7
0
/*
   applies and consumes the following options: 
   PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
   OFUNC_OFFSET
   OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER,
   OPT_GROUP, OPT_CLOEXEC
 */
static
int _xioopen_rawip_sendto(const char *hostname, const char *protname,
			  struct opt *opts, int xioflags, xiofile_t *xxfd,
			  unsigned groups, int *pf) {
   char *garbage;
   xiosingle_t *xfd = &xxfd->stream;
   int rw = (xioflags&XIO_ACCMODE);
   union sockaddr_union us;
   socklen_t uslen;
   int feats = 1;	/* option bind supports only address, not port */
   int socktype = SOCK_RAW;
   int ipproto;
   bool needbind = false;
   int result;

   if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
      Error3("xioopen_rawip_sendto(\"%s:%s\",,): protocol number exceeds 255 (%u)",
	     hostname, protname, ipproto);
      return STAT_NORETRY;
   } else if (*garbage) {
      Warn2("xioopen_rawip_sendto(\"%s:%s\",,): trailing garbage in protocol specification",
	     hostname, protname);
      /*return STAT_NORETRY;*/
   }

   retropt_int(opts, OPT_PROTOCOL_FAMILY, pf);

   /* ...res_opts[] */
   if (applyopts_single(xfd, opts, PH_INIT) < 0)  return -1;
   applyopts(-1, opts, PH_INIT);

   xfd->salen = sizeof(xfd->peersa);
   if ((result =
	xiogetaddrinfo(hostname, NULL, *pf, socktype, ipproto,
		       &xfd->peersa, &xfd->salen,
		       xfd->para.socket.ip.res_opts[0],
		       xfd->para.socket.ip.res_opts[1]))
       != STAT_OK) {
      return result;
   }
   if (*pf == PF_UNSPEC) {
      *pf = xfd->peersa.soa.sa_family;
   }

   uslen = socket_init(*pf, &us);

   xfd->dtype = XIODATA_RECVFROM_SKIPIP;

   if (retropt_bind(opts, *pf, socktype, ipproto, &us.soa, &uslen, feats,
		    xfd->para.socket.ip.res_opts[0],
		    xfd->para.socket.ip.res_opts[1]) != STAT_NOACTION) {
      needbind = true;
   }
   if ((result =
	_xioopen_dgram_sendto(needbind?&us:NULL, uslen,
			      opts, xioflags, xfd, groups, *pf, socktype,
			      ipproto)) != STAT_OK) {
      return result;
   }
   if (XIOWITHWR(rw))   xfd->wfd = xfd->rfd;
   if (!XIOWITHRD(rw))  xfd->rfd = -1;
   return STAT_OK;
}