示例#1
0
/* open for writing:
   if the filesystem entry already exists, the data is appended
   if it does not exist, a file is created and the data is appended
*/
static int xioopen_open(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, unsigned groups, int dummy1, int dummy2, int dummy3) {
   const char *filename = argv[1];
   int rw = (xioflags & XIO_ACCMODE);
   bool exists;
   bool opt_unlink_close = false;
   int result;

   /* remove old file, or set user/permissions on old file; parse options */
   if ((result = _xioopen_named_early(argc, argv, fd, groups, &exists, opts)) < 0) {
      return result;
   }

   retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
   if (opt_unlink_close) {
      if ((fd->stream.unlink_close = strdup(filename)) == NULL) {
	 Error1("strdup(\"%s\"): out of memory", filename);
      }
      fd->stream.opt_unlink_close = true;
   }

   Notice3("opening %s \"%s\" for %s",
	   filetypenames[(result&S_IFMT)>>12], filename, ddirection[rw]);
   if ((result = _xioopen_open(filename, rw, opts)) < 0)
      return result;
   fd->stream.fd = result;

#if WITH_TERMIOS
   if (Isatty(fd->stream.fd)) {
      if (Tcgetattr(fd->stream.fd, &fd->stream.savetty) < 0) {
	 Warn2("cannot query current terminal settings on fd %d: %s",
	       fd->stream.fd, strerror(errno));
      } else {
	 fd->stream.ttyvalid = true;
      }
   }
#endif /* WITH_TERMIOS */

   applyopts_named(filename, opts, PH_FD);
   applyopts(fd->stream.fd, opts, PH_FD);
   applyopts_cloexec(fd->stream.fd, opts);

   applyopts_fchown(fd->stream.fd, opts);

   if ((result = _xio_openlate(&fd->stream, opts)) < 0)
      return result;

   return 0;
}
示例#2
0
static int xioopen_creat(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) {
   const char *filename = argv[1];
   int rw = (xioflags&XIO_ACCMODE);
   int fd;
   bool exists;
   bool opt_unlink_close = false;
   int result;

   /* remove old file, or set user/permissions on old file; parse options */
   if ((result = _xioopen_named_early(argc, argv, xfd, groups, &exists, opts)) < 0) {
      return result;
   }

   retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);
   if (opt_unlink_close) {
      if ((xfd->stream.unlink_close = strdup(filename)) == NULL) {
	 Error1("strdup(\"%s\"): out of memory", filename);
      }
      xfd->stream.opt_unlink_close = true;
   }

   Notice2("creating regular file \"%s\" for %s", filename, ddirection[rw]);
   if ((fd = _xioopen_creat(filename, rw, opts)) < 0)
      return fd;
   if (XIOWITHRD(rw))  xfd->stream.rfd = fd;
   if (XIOWITHWR(rw))  xfd->stream.wfd = fd;

   applyopts_named(filename, opts, PH_PASTOPEN);
   if ((result = applyopts2(fd, opts, PH_PASTOPEN, PH_LATE2)) < 0)
      return result;

   applyopts_cloexec(fd, opts);

   applyopts_fchown(fd, opts);

   if ((result = _xio_openlate(&xfd->stream, opts)) < 0)
      return result;

   return 0;
}
示例#3
0
文件: xio-udp.c 项目: erluko/socat
/* we expect the form: port */
int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
			   int xioflags, xiofile_t *fd,
			  unsigned groups, int pf, int ipproto,
			  int protname) {
   const char *portname = argv[1];
   union sockaddr_union us;
   union sockaddr_union themunion;
   union sockaddr_union *them = &themunion;
   int socktype = SOCK_DGRAM;
   struct pollfd readfd;
   bool dofork = false;
   pid_t pid;
   char *rangename;
   char infobuff[256];
   unsigned char buff1[1];
   socklen_t uslen;
   socklen_t themlen;
   int result;

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

   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
   }

   retropt_socket_pf(opts, &pf);

   if (applyopts_single(&fd->stream, opts, PH_INIT) < 0)  return -1;
   applyopts(-1, opts, PH_INIT);

   uslen = socket_init(pf, &us);
   retropt_bind(opts, pf, socktype, IPPROTO_UDP,
		(struct sockaddr *)&us, &uslen, 1,
		fd->stream.para.socket.ip.res_opts[1],
		fd->stream.para.socket.ip.res_opts[0]);

   if (false) {
      ;
#if WITH_IP4
   } else if (pf == PF_INET) {
      us.ip4.sin_port = parseport(portname, ipproto);
#endif
#if WITH_IP6
   } else if (pf == PF_INET6) {
      us.ip6.sin6_port = parseport(portname, ipproto);
#endif
   } else {
      Error1("xioopen_ipdgram_listen(): unknown address family %d", pf);
   }

   retropt_bool(opts, OPT_FORK, &dofork);

   if (dofork) {
      if (!(xioflags & XIO_MAYFORK)) {
	 Error("option fork not allowed here");
	 return STAT_NORETRY;
      }
   }

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

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

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

   if (dofork) {
      xiosetchilddied();	/* set SIGCHLD handler */
   }

   while (true) {	/* we loop with fork or prohibited packets */
      /* now wait for some packet on this datagram socket, get its sender
	 address, connect there, and return */
      int one = 1;
      char infobuff[256];
      union sockaddr_union _sockname;
      union sockaddr_union *la = &_sockname;	/* local address */

      if ((fd->stream.fd = xiosocket(opts, pf, socktype, ipproto, E_ERROR)) < 0) {
	 return STAT_RETRYLATER;
      }
      applyopts(fd->stream.fd, opts, PH_PASTSOCKET);
      if (Setsockopt(fd->stream.fd, opt_so_reuseaddr.major,
		     opt_so_reuseaddr.minor, &one, sizeof(one)) < 0) {
	 Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd"): %s",
	       fd->stream.fd, opt_so_reuseaddr.major,
	       opt_so_reuseaddr.minor, one, sizeof(one), strerror(errno));
      }
      applyopts_cloexec(fd->stream.fd, opts);
      applyopts(fd->stream.fd, opts, PH_PREBIND);
      applyopts(fd->stream.fd, opts, PH_BIND);
      if (Bind(fd->stream.fd, &us.soa, uslen) < 0) {
	 Error4("bind(%d, {%s}, "F_Zd"): %s", fd->stream.fd,
		sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)),
		uslen, strerror(errno));
	 return STAT_RETRYLATER;
      }
      /* under some circumstances bind() fills sockaddr with interesting info. */
      if (Getsockname(fd->stream.fd, &us.soa, &uslen) < 0) {
	 Error4("getsockname(%d, %p, {%d}): %s",
		fd->stream.fd, &us.soa, uslen, strerror(errno));
      }
      applyopts(fd->stream.fd, opts, PH_PASTBIND);

      Notice1("listening on UDP %s",
	      sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)));
      readfd.fd = fd->stream.fd;
      readfd.events = POLLIN|POLLERR;
      while (xiopoll(&readfd, 1, NULL) < 0) {
	 if (errno != EINTR)  break;
      }

      themlen = socket_init(pf, them);
      do {
	 result = Recvfrom(fd->stream.fd, buff1, 1, MSG_PEEK,
			     &them->soa, &themlen);
      } while (result < 0 && errno == EINTR);
      if (result < 0) {
	 Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_Zu"}): %s",
		fd->stream.fd, buff1,
		sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
		themlen, strerror(errno));
	 return STAT_RETRYLATER;
      }

      Notice1("accepting UDP connection from %s",
	      sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)));

      if (xiocheckpeer(&fd->stream, them, la) < 0) {
	 /* drop packet */
	 char buff[512];
	 Recv(fd->stream.fd, buff, sizeof(buff), 0);	/* drop packet */
	 Close(fd->stream.fd);
	 continue;
      }
      Info1("permitting UDP connection from %s",
	    sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)));

      if (dofork) {
	 pid = xio_fork(false, E_ERROR);
	 if (pid < 0) {
	    return STAT_RETRYLATER;
	 }

	 if (pid == 0) {	/* child */
	    break;
	 }

	 /* server: continue loop with socket()+recvfrom() */
	 /* when we dont close this we get awkward behaviour on Linux 2.4:
	    recvfrom gives 0 bytes with invalid socket address */
	 if (Close(fd->stream.fd) < 0) {
	    Info2("close(%d): %s", fd->stream.fd, strerror(errno));
	 }
	 Sleep(1);	/*! give child a chance to consume the old packet */

	 continue;
      }
      break;
   }

   applyopts(fd->stream.fd, opts, PH_CONNECT);
   if ((result = Connect(fd->stream.fd, &them->soa, themlen)) < 0) {
      Error4("connect(%d, {%s}, "F_Zd"): %s",
	     fd->stream.fd,
	     sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
	     themlen, strerror(errno));
      return STAT_RETRYLATER;
   }

   /* set the env vars describing the local and remote sockets */
   if (Getsockname(fd->stream.fd, &us.soa, &uslen) < 0) {
      Warn4("getsockname(%d, %p, {%d}): %s",
	    fd->stream.fd, &us.soa, uslen, strerror(errno));
   }
   xiosetsockaddrenv("SOCK", &us,  uslen,   IPPROTO_UDP);
   xiosetsockaddrenv("PEER", them, themlen, IPPROTO_UDP);

   fd->stream.howtoend = END_SHUTDOWN;
   applyopts_fchown(fd->stream.fd, opts);
   applyopts(fd->stream.fd, opts, PH_LATE);

   if ((result = _xio_openlate(&fd->stream, opts)) < 0)
      return result;

   return 0;
}
示例#4
0
static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) {
   char *tundevice = NULL;
   char *tunname = NULL, *tuntype = NULL;
   int pf = /*! PF_UNSPEC*/ PF_INET;
   struct xiorange network;
   bool no_pi = false;
   const char *namedargv[] = { "tun", NULL, NULL };
   int rw = (xioflags & XIO_ACCMODE);
   bool exists;
   struct ifreq ifr;
   int sockfd;
   char *ifaddr;
   int result;

   if (argc > 2 || argc < 0) {
      Error2("%s: wrong number of parameters (%d instead of 0 or 1)",
	     argv[0], argc-1);
   }

   if (retropt_string(opts, OPT_TUN_DEVICE, &tundevice) != 0) {
      tundevice = strdup("/dev/net/tun");
   }

   /*! socket option here? */
   retropt_socket_pf(opts, &pf);

   namedargv[1] = tundevice;
   /* open the tun cloning device */
   if ((result = _xioopen_named_early(2, namedargv, xfd, groups, &exists, opts)) < 0) {
      return result;
   }

   /*========================= the tunnel interface =========================*/
   Notice("creating tunnel network interface");
   if ((result = _xioopen_open(tundevice, rw, opts)) < 0)
      return result;
   xfd->stream.fd = result;

   /* prepare configuration of the new network interface */
   memset(&ifr, 0,sizeof(ifr));

   if (retropt_string(opts, OPT_TUN_NAME, &tunname) == 0) {
      strncpy(ifr.ifr_name, tunname, IFNAMSIZ);	/* ok */
      free(tunname);
   } else {
      ifr.ifr_name[0] = '\0';
   }

   ifr.ifr_flags = IFF_TUN;
   if (retropt_string(opts, OPT_TUN_TYPE, &tuntype) == 0) {
      if (!strcmp(tuntype, "tap")) {
	 ifr.ifr_flags = IFF_TAP;
      } else if (strcmp(tuntype, "tun")) {
	 Error1("unknown tun-type \"%s\"", tuntype);
      }
   }

   if (retropt_bool(opts, OPT_IFF_NO_PI, &no_pi) == 0) {
      if (no_pi) {
	 ifr.ifr_flags |= IFF_NO_PI;
#if 0 /* not neccessary for now */
      } else {
	 ifr.ifr_flags &= ~IFF_NO_PI;
#endif
      }
   }

   if (Ioctl(xfd->stream.fd, TUNSETIFF, &ifr) < 0) {
      Error3("ioctl(%d, TUNSETIFF, {\"%s\"}: %s",
	     xfd->stream.fd, ifr.ifr_name, strerror(errno));
      Close(xfd->stream.fd);
   }

   /*===================== setting interface properties =====================*/

   /* we seem to need a socket for manipulating the interface */
   if ((sockfd = Socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
      Error1("socket(PF_INET, SOCK_DGRAM, 0): %s", strerror(errno));
      sockfd = xfd->stream.fd;	/* desparate fallback attempt */
   }

   /*--------------------- setting interface address and netmask ------------*/
   if (argc == 2) {
       if ((ifaddr = strdup(argv[1])) == NULL) {
          Error1("strdup(\"%s\"): out of memory", argv[1]);
          return STAT_RETRYLATER;
       }
       if ((result = xioparsenetwork(ifaddr, pf, &network)) != STAT_OK) {
          /*! recover */
          return result;
       }
       socket_init(pf, (union sockaddr_union *)&ifr.ifr_addr);
       ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr =
          network.netaddr.ip4.sin_addr;
       if (Ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
          Error4("ioctl(%d, SIOCSIFADDR, {\"%s\", \"%s\"}: %s",
             sockfd, ifr.ifr_name, ifaddr, strerror(errno));
       }
       ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr =
          network.netmask.ip4.sin_addr;
       if (Ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
          Error4("ioctl(%d, SIOCSIFNETMASK, {\"0x%08u\", \"%s\"}, %s",
             sockfd, ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr,
             ifaddr, strerror(errno));
       }
       free(ifaddr);
   }
   /*--------------------- setting interface flags --------------------------*/
   applyopts_single(&xfd->stream, opts, PH_FD);

   if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
      Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
	     sockfd, ifr.ifr_name, strerror(errno));
   }
   Debug2("\"%s\": system set flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);
   ifr.ifr_flags |= xfd->stream.para.tun.iff_opts[0];
   ifr.ifr_flags &= ~xfd->stream.para.tun.iff_opts[1];
   Debug2("\"%s\": xio merged flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);
   if (Ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
      Error4("ioctl(%d, SIOCSIFFLAGS, {\"%s\", %hd}: %s",
	     sockfd, ifr.ifr_name, ifr.ifr_flags, strerror(errno));
   }
   ifr.ifr_flags = 0;
   if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
      Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
	     sockfd, ifr.ifr_name, strerror(errno));
   }
   Debug2("\"%s\": resulting flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);


#if LATER
   applyopts_named(tundevice, opts, PH_FD);
#endif
   applyopts(xfd->stream.fd, opts, PH_FD);
   applyopts_cloexec(xfd->stream.fd, opts);

   applyopts_fchown(xfd->stream.fd, opts);

   if ((result = _xio_openlate(&xfd->stream, opts)) < 0)
      return result;

   return 0;
}