inetdtap.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. # -*- test-case-name: twisted.runner.test.test_inetdtap -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. Twisted inetd TAP support
  6. The purpose of inetdtap is to provide an inetd-like server, to allow Twisted to
  7. invoke other programs to handle incoming sockets.
  8. This is a useful thing as a "networking swiss army knife" tool, like netcat.
  9. """
  10. import pwd, grp, socket
  11. from twisted.runner import inetd, inetdconf
  12. from twisted.python import log, usage
  13. from twisted.internet.protocol import ServerFactory
  14. from twisted.application import internet, service as appservice
  15. # Protocol map
  16. protocolDict = {'tcp': socket.IPPROTO_TCP, 'udp': socket.IPPROTO_UDP}
  17. class Options(usage.Options):
  18. """
  19. To use it, create a file named `sample-inetd.conf` with:
  20. 8123 stream tcp wait some_user /bin/cat -
  21. You can then run it as in the following example and port 8123 became an
  22. echo server.
  23. twistd -n inetd -f sample-inetd.conf
  24. """
  25. optParameters = [
  26. ['rpc', 'r', '/etc/rpc', 'DEPRECATED. RPC procedure table file'],
  27. ['file', 'f', '/etc/inetd.conf', 'Service configuration file']
  28. ]
  29. optFlags = [['nointernal', 'i', "Don't run internal services"]]
  30. compData = usage.Completions(
  31. optActions={"file": usage.CompleteFiles('*.conf')}
  32. )
  33. def makeService(config):
  34. s = appservice.MultiService()
  35. conf = inetdconf.InetdConf()
  36. with open(config['file']) as f:
  37. conf.parseFile(f)
  38. for service in conf.services:
  39. protocol = service.protocol
  40. if service.protocol.startswith('rpc/'):
  41. log.msg('Skipping rpc service due to lack of rpc support')
  42. continue
  43. if (protocol, service.socketType) not in [('tcp', 'stream'),
  44. ('udp', 'dgram')]:
  45. log.msg('Skipping unsupported type/protocol: %s/%s'
  46. % (service.socketType, service.protocol))
  47. continue
  48. # Convert the username into a uid (if necessary)
  49. try:
  50. service.user = int(service.user)
  51. except ValueError:
  52. try:
  53. service.user = pwd.getpwnam(service.user)[2]
  54. except KeyError:
  55. log.msg('Unknown user: ' + service.user)
  56. continue
  57. # Convert the group name into a gid (if necessary)
  58. if service.group is None:
  59. # If no group was specified, use the user's primary group
  60. service.group = pwd.getpwuid(service.user)[3]
  61. else:
  62. try:
  63. service.group = int(service.group)
  64. except ValueError:
  65. try:
  66. service.group = grp.getgrnam(service.group)[2]
  67. except KeyError:
  68. log.msg('Unknown group: ' + service.group)
  69. continue
  70. if service.program == 'internal':
  71. if config['nointernal']:
  72. continue
  73. # Internal services can use a standard ServerFactory
  74. if service.name not in inetd.internalProtocols:
  75. log.msg('Unknown internal service: ' + service.name)
  76. continue
  77. factory = ServerFactory()
  78. factory.protocol = inetd.internalProtocols[service.name]
  79. else:
  80. factory = inetd.InetdFactory(service)
  81. if protocol == 'tcp':
  82. internet.TCPServer(service.port, factory).setServiceParent(s)
  83. elif protocol == 'udp':
  84. raise RuntimeError("not supporting UDP")
  85. return s