Updated 2007-12-14 21:42:23 by dkf

The script below will create an array of common tcp port services as listed in an /etc/services file. It will write the data to a file named "tcpports" creating an array of the same name. The file can then either be sourced by your script or you can clip/paste it into a script.

It's a simple thing but quite handy if/when needed.

Mike Tuxford
 # make sure we can find the services file
 if {![file exists /etc/services]} {
   puts "Can't find /etc/services file"
   exit
 } else {
   set ifile [open /etc/services r]
   set rawData [split [read $ifile] \n]
   close $ifile
 }
 
 # make sure we can create the output file
 if {[catch {open ./tcpports w} ofile]} {
   puts "Can't create output file ./tcpports"
   exit
 }
 
 puts $ofile "global tcpports\narray set tcpports {"
 flush $ofile
 set oline "  "
 
 for {set i 0} {$i < [llength $rawData]} {incr i} {
   set line [lindex $rawData $i]
   # ignore comments and empty lines
   if {[string index $line 0] == "#" ||
       [string index $line 0] == " " ||
       [string index $line 0] == ""} {
     continue
   }
   # ignore if not tcp
   if {[lindex [split [lindex $line 1]  "/"] 1] != "tcp"} {
     continue
   }
   # parse the data
   set oline "$oline [lindex [split [lindex $line 1]  "/"] 0] [lindex $line 0]"
   # add it to the array file if greater than 70 chars
   if {[string length $oline] > 70} {
     puts $ofile $oline
     flush $ofile
     set oline "  "
   }
 }
 if {[string length $oline] > 2} {
   puts $ofile $oline
   flush $ofile
 }
 puts $ofile "};#Mike Tuxford"
 flush $ofile
 catch {close $ofile}

Below is a script for testing port service availability that uses the
array generated by the script above.

 #!/usr/bin/tclsh
 #
 #################################
 # Mike Tuxford 2003
 #
 array set tcpports {
    1 tcpmux 7 echo 9 discard 11 systat 13 daytime 15 netstat 17 qotd 18 msp
    19 chargen 20 ftp-data 21 ftp 22 ssh 23 telnet 25 smtp 37 time 42 nameserver
    43 whois 50 re-mail-ck 53 domain 57 mtp 67 bootps 68 bootpc 70 gopher
    77 rje 79 finger 80 www 87 link 88 kerberos 95 supdup 101 hostnames 102 iso-tsap
    105 csnet-ns 107 rtelnet 109 pop2 110 pop3 111 sunrpc 113 auth 115 sftp
    117 uucp-path 119 nntp 123 ntp 129 pwdgen 137 netbios-ns 138 netbios-dgm
    139 netbios-ssn 143 imap2 163 cmip-man 164 cmip-agent 174 mailq 177 xdmcp
    178 nextstep 179 bgp 191 prospero 194 irc 199 smux 201 at-rtmp 202 at-nbp
    204 at-echo 206 at-zis 209 qmtp 210 z3950 213 ipx 220 imap3 345 pawserv
    346 zserv 347 fatserv 369 rpc2portmap 370 codaauth2 372 ulistserv 389 ldap
    443 https 444 snpp 445 microsoft-ds 487 saft 610 npmp-local 611 npmp-gui
    612 hmmp-ind 631 ipp 512 exec 513 login 514 shell 515 printer 526 tempo
    530 courier 531 conference 532 netnews 538 gdomap 540 uucp 543 klogin
    544 kshell 548 afpovertcp 556 remotefs 563 nntps 587 submission 636 ldaps
    655 tinc 706 silc 749 kerberos-adm 765 webster 873 rsync 989 ftps-data
    990 ftps 992 telnets 993 imaps 994 ircs 995 pop3s 1080 socks 1352 lotusnote
    1524 ingreslock 1525 prospero-np 1645 datametrics 1646 sa-msg-port 1812 radius
    1813 radius-acct 2101 rtcm-sc104 2401 cvspserver 2430 venus 2431 venus-se
    2432 codasrv 2433 codasrv-se 2583 mon 2628 dict 3050 gds_db 3130 icpv2
    3306 mysql 3632 distcc 5002 rfe 5222 jabber-client 5269 jabber-server
    5308 cfengine 5432 postgres 6000 x11 6001 x11-1 6002 x11-2 6003 x11-3
    6004 x11-4 6005 x11-5 6006 x11-6 6007 x11-7 7000 afs3-fileserver 7001 afs3-callback
    7002 afs3-prserver 7003 afs3-vlserver 7004 afs3-kaserver 7005 afs3-volser
    7006 afs3-errors 7007 afs3-bos 7008 afs3-update 7009 afs3-rmtsys 7100 font-service
    22273 wnn6 750 kerberos4 751 kerberos_master 754 krb_prop 760 krbupdate
    761 kpasswd 901 swat 1109 kpop 2053 knetd 2105 eklogin 2111 kx 2121 iprop
    871 supfilesrv 1127 supfiledbg 98 linuxconf 106 poppassd 406 imsp 465 ssmtp
    607 nqs 775 moira_db 777 moira_update 808 omirr 1001 customs 1099 rmiregistry
    1178 skkserv 1236 rmtcfg 1300 wipld 1313 xtel 1314 xtelw 1529 support
    2000 sieve 2003 cfinger 2010 ndtp 2121 frox 2150 ninstall 2600 zebrasrv
    2601 zebra 2602 ripd 2603 ripngd 2604 ospfd 2605 bgpd 2606 ospf6d 2988 afbackup
    2989 afmbackup 4224 xtell 4557 fax 4559 hylafax 5151 pcrd 5354 noclog
    5355 hostmon 5674 mrtd 5675 bgpsim 5680 canna 6566 sane 6667 ircd 8021 zope-ftp
    8080 webcache 8081 tproxy 8088 omniorb 9673 zope 10081 kamanda 10082 amandaidx
    10083 amidxtape 11201 smsqp 15345 xpilot 17004 sgi-cad 20011 isdnlog
    20012 vboxd 24554 binkp 27374 asp 57000 dircproxy 60177 tfido 60179 fido
 };#Mike Tuxford
 
 proc parseCommandLine {} {
   global argv opt
   if {[string match -nocase "*-h*" [lindex $argv 0]] || \
       [llength $argv] < 2} {
     puts "Syntax: getport <host|IP> <port|port-range>"
     exit
   }
   set opt(host) [lindex $argv 0]
   if {[string is integer [lindex $argv 1]]} {
     set opt(ports) "[lindex $argv 1] [lindex $argv 1]"
   } else {
     set opt(ports) [split [lindex $argv 1] "-"]
     set opt(ports) "[lindex $opt(ports) 0] [lindex $opt(ports) 1]"
     if {![string is integer [lindex $opt(ports) 0]] ||
         ![string is integer [lindex $opt(ports) 1]] ||
         [lindex $opt(ports) 0] >= [lindex $opt(ports) 1]} {
       puts "Bad port range: [lindex $argv 1]"
       exit
     }
   }
   return
 }
 
 proc output {msg} {
   global opt tcpports
   if {[info exists tcpports($opt(port))]} {
     set prefix "$opt(port) ($tcpports($opt(port))\)"
   } else {
     set prefix $opt(port)
   }
   puts "$prefix $msg"
   return
 }
 
 proc netEventHandler {} {
   global fd status
   if {[eof $fd(connect)] != 0} {
     output "Connection closed by remote host"
   } else {
     set data [gets $fd(connect)]
     if {$data != ""} {
       set msg "open \[$data\]"
     } else {
       set msg "open"
     }
     output $msg
   }
   catch {close $fd(connect)}
   after cancel $status(after)
   set status(connect) "OK"
   return
 }
 
 proc disco {} {
   global fd status
   if {$status(connect) == "OK"} {
     return
   } else {
     output "Dropped or filtered by host"
     catch {close $fd(connect)}
     after cancel $status(after)
     set status(connect) "OK"
   }
   return
 }
 
 proc bgerror {args} {
   global fd status
   # switch used for expandability
   switch -glob -- $args {
     *refused* {
       output "open but connection refused."
       catch {close $fd(connect)}
     }
     default {
       puts "bgerror: $args"
       exit
     }
   }
   after cancel $status(after)
   set status(connect) "OK"
   return
 }
 
 ###################
 parseCommandLine
 puts "Host: $opt(host)"
 for {set opt(port) [lindex $opt(ports) 0]} \
     {$opt(port) <= [lindex $opt(ports) 1]} {incr opt(port)} {
   set status(connect) "wait"
   if {[catch {socket -async $opt(host) $opt(port)} fd(connect)]} {
     puts "Failed to connect to: $opt(host) on port: $opt(port)"
     exit
   } else {
     set status(after) [after 5000 disco]
     fconfigure $fd(connect) -blocking 0
     fileevent $fd(connect) readable netEventHandler
     vwait status(connect)
   }
 }

An example of the output...
 burp:/tcl/s/getport# ./getport 127.0.0.1 21-25
 Host: 127.0.0.1
 21 (ftp) Dropped or filtered by host
 22 (ssh) Dropped or filtered by host
 23 (telnet) open
 24 open but connection refused.
 25 (smtp) open [220 burp ESMTP Exim 3.36 #1 Sun, 29 Jun 2003 12:30:59 -0700]

See also: tkwhois