Configuring Dante Socks 101

Brief explanation on how to configure Dante Socks server (Dante v 1.4.1). (/etc/sockd/sockd.conf) This example has an annotated copy of sockd.conf to use as an example.

Dante Socks Encapsulation

Dante Socks is a handy little proxy.  It should only be used internally to provide back-end access.  From the user to the Dante Socks proxy server only 1080/TCP needs to be opened through the firewall.  All ports are encapsulated inside of SOCKS (1080/TCP).  The Dante Socks proxy will then strip off the encapsulation.  From the Dante socks proxy new firewall rules will need to be created.  The source will be the Dante Socks external IP address.  At this time the real ports need to be added to any firewall rules.  See the picture below.

Dante Socks Proxy Encapsulation

Dante Socks Proxy Encapsulation

Compiling the Code

These directions assume you have compiled the code from the source.  And that you are running v1.4.x.  See this post for directions on compiling the code from the source code.

Configuration Steps

These configuration steps are designed for a box running systemd.

Create a Group and User

The Dante Socks server should run as a non-root user.  It starts as root and forks.  The PID file resides in '/var/run/sockd.pid' and this requires root.  A new group and ID will be created.  This ID does not require a password.  It is just a process ID.

  • groupadd -g 1080 sockd
  • useradd -g sockd -G sockd -u 1080 -c 'Dante Socks Process ID' sockd

Create the Systemd Unit Service File

The user generated unit service files are created in '/etc/systemd/system'.  Create a new file named 'sockd.service'.  It is owned by 0:0.  And the permissions are 0644.  The contents of this file are shown below.

# cat /etc/systemd/system/sockd.service
[Unit]
Description=Dante Socks Proxy v1.4.1
After=network.target

[Service]
Type=forking
PIDFile=/var/run/sockd.pid
ExecStart=/usr/local/sockd/sbin/sockd -D -f /etc/sockd/sockd.conf
ExecReload=/bin/kill -HUP ${MAINPID}
KillMode=process
Restart=on-failure

[Install]
WantedBy=multi-user.target graphical.target

Now add this service unit to systemd and have it start at boot.

  • systemctl daemon-reload
  • systemctl enable sockd

This will create the appropriate sym links.  See the example below.

# systemctl enable sockd
Created symlink from /etc/systemd/system/multi-user.target.wants/sockd.service to /etc/systemd/system/sockd.service.
Created symlink from /etc/systemd/system/graphical.target.wants/sockd.service to /etc/systemd/system/sockd.service.

Edit /etc/sockd/sockd.conf

Below is a annotated sockd.conf file.  It includes information from the sockd.conf man page.  And it includes a number of commented out options.  The user needs to understand basic networking so that the user can edit the client and socks rules properly.

In this example the client and socks rules are configured to use no authentication.  While SSH is encrypted the socks tunnel is NOT encrypted.  Anyone can sniff the ID and password.  Unless 'gssapi' authentication is configured.  This uses kerberos.  Plus enabling ID and password forces the user to have an account on the Dante Socks server.  This risk can be mediated by creating a SSH chroot jail.  Ideally an authentication firewall will be placed in front of the socks server.  This can be TACACS+ or some other method for authentication.  See the tcpdump snippet below to clearly see the ID and password.

00:56:04.685069 IP 192.168.1.2.65026 > 192.168.1.105.1080: Flags [P.], seq 5:19, ack 3, win 256, length 14
E..6;.@...;........i...8<$......P...|.....pi raspberry

All of the logging is commented out in this configuration.  Since we are using systemd INIT we can let systemd perform logging using journald.

Refer to the official documentation for help setting up PAM authentication.  Keep in mind that this ID and password will be in clear text as well.

The sockd.conf file has examples for setting up libwrap.  (TCP Wrappers)  The libwrap lines in the client and socks rules are commented out.  Uncomment these lines if libwrap is desired.  The hosts.allow file has to have a 'sockd' line with the appropriate networks.

The user needs to edit the bold blue items.

# Sample /etc/sockd/sockd.conf
#
# This file has additional annotations from the MAN page
# for sockd.conf. It is taken from the sample sockd.conf
# file from the source files.
# It covers the basic setup of a proxy server.
#
# For more configuration information refer to the official docs
# https://www.inet.no/dante/doc/
#
# Infomration on Dante Socks Server Chaining
# https://www.inet.no/dante/doc/1.4.x/config/chaining.html
#
# Information on CPU Scheduling and Affinity
# https://www.inet.no/dante/doc/1.4.x/config/cpu.html
#
# Information on Dante Socks Traffic Monitoring
# https://www.inet.no/dante/doc/1.4.x/config/monitors.html
#
#
###############################################################
##### SECTION 1 ##### SECTION 1 ##### SECTION 1 #########
################## Server Settings ############################
###############################################################

# Debug Logging - Change value and restart socks as required
#   debug: 0 = No debug logging
#   debug: 1 = Some debug logging
#   debug: 2 = Verbose debug logging
debug: 0

# logoutput
#   This value controls where the server sends logoutput. It can be set to syslog[/facil-
#   ity], stdout, stderr, a filename, or a combination. The default is nowhere. Note that
#   if errorlog is also set, there will be a overlap between what is logged there (errors
#   only), and what will be logged here (errors, and everything else).
#   NOTE: Use journald logging instead
#   NOTE: Make sure you setup log rotation on sockd.log
#logoutput: syslog/local5 /var/log/sockd.log

# OPTIONAL - Error Log - Dedicated space for serious global errors
# NOTE: Make sure you setup log rotation on sockd.errlog
#errorlog: syslog/local7 /var/log/sockd.errlog

# OPTIONAL - Logging of traffic related failure warnings such as:
#   1) Routing Errors 2) Connection Refused Errors 3) DNS Failures
#
# Uncomment to enable logging of routing failure warnings
#external.log.warning.error: no-route
#internal.log.warning.error: no-route
#
# Uncomment to log DNS related errors on the external interface
#external.log.warning.error: dns-any
#
# Uncomment to log target connection refused - server app has crashed
# on the external interface
#external.log.warning.error: ECONNREFUSED EAI_AGAIN

# The server will bind to the address 10.1.1.1, port 1080 and will only
# accept connections going to that address.
internal: 10.1.1.1 port = 1080
# Alternatively, the interface name can be used instead of the address.
#internal: eth0 port = 1080

# all outgoing connections from the server will use the IP address
external: 192.168.1.1

# list over acceptable authentication methods, order of preference.
# An authentication method not set here will never be selected.
#
# If the socksmethod field is not set in a rule, the global
# socksmethod is filled in for that rule.
#

# Global methods for client-rules before socksmethod
# Only IP-Address of client - auth passed to socksmethod
# Values = pam.address pam.any none rfc931
#
clientmethod: none

# Global methods for socks-rules.
# Values = bsdauth // BSD Authentication
#    gssapi // kerberos
#    none // no authentication
#    pam.any // any PAM auth - limited value
#    pam.address // IP-based (rhosts) PAM auth
#    pam.username // id/pass PAM auth
#    rfc931 // client rfc931 ident username passwd match system passwd
#    username // ID/pass SOCKS accesses passwd file directly
#
socksmethod: none

#
# User identities, an important section.
#

# user.privileged
#  Username which will be used for doing privileged operations. If you need
#  special privileges to read the sockd.conf file or to write the sockd.pid
#  file (you can create it manually before starting sockd), have anything
#  in your configuration that requires binding privileged TCP/UDP ports
#  (ports below 1024), or use some sort of password-based authentication,
#  this probably needs to be set to root.
#  If not, you can probably set it to the same value as user.unprivileged.
#  Creating /var/run/sockd.pid on some Linux distros requires root.
user.privileged: root

# when running as usual, it will use the unprivileged userid of "sockd".
#
# user.unprivileged
#   User which the server runs as most of the time. This should be an id
#   with as little privileges as possible. It is recommended that a
#   separate userid is created for this purpose.
user.unprivileged: sockd

# user.libwrap
#   User used to execute libwrap commands. Normally this should be
#   the same as user.unprivileged (Delete if libwrap not compiled or not # #    used.)
user.libwrap: sockd

#
# Some options to help clients with compatibility:
#

# compatibility
#    With the sameport keyword, the server attempts to use the same port on the
#   server's external side as the client used on the server's internal side.
#   This is normally the default, but when this option is given it will be done
#   with privileged ports also, meaning if a client connects to Dante from a
#   privileged port, Dante will attempt to connect to the target destination from
#   a privileged port too. There can be security issues involved with this, so
#   normally this option should not be set.
#   This will usually require user.privileged to be set to 'root'.
#compatibility: sameport

# If you are using the Inferno Nettverk bind extension and have trouble
# running servers via the server, you might try setting this.
#compatibility: reuseaddr

#
# The Dante server supports some extensions to the socks protocol.
# These require that the socks client implements the same extension and
# can be enabled using the "extension" keyword.
#
# NOTE: Inferno is considering deprecating the BIND extension. Using
# it will through up a warning in the logs. Try not using it first.
#extension: bind

#
# Misc options.
#

# timeout.negotiate
#   The number of seconds a client can spend negotiating with the Dante
#   server for a socks session before Dante will close the connection to
#   the client. The default is 30. Set it to 0 for forever, though that
#   is strongly discouraged.

# how many seconds can pass from when a client connects til it has
# sent us it's request? Adjust according to your network performance
# and methods supported.
timeout.negotiate: 30 # on a lan, this should be enough.

# timeout.io
#   The number of seconds an established connection can be idle. The
#   default is 0, meaning forever. See also the "-n" option in the
#   sockd(8) manpage. Individual timeouts can be set for TCP and UDP
#   by suffixing io with ".<protocolname>", i.e. timeout.io.tcp
#   or timeout.io.udp. Individual timeouts can also be set within rules,
#   using the same syntax. The timeout set in the rule will then override
#   the default timeouts for clients matching the rule.

# how many seconds can the client and it's peer idle without sending
# any data before we dump it? Unless you disable tcp keep-alive for
# some reason, it's probably best to set this to 0, which is
# "forever".
timeout.io: 0 # or perhaps 86400, for a day.

# timeout.connect
#   The number of seconds the server will wait for a connect initiated on
#   behalf of the socks-client to complete. The default is 30. Setting
#   it to 0 will use the systems default.
timeout.connect: 30

# enable libwrap /etc/hosts.allow and /etc/hosts.deny access control
libwrap.hosts_access: yes

# srchost
#   This keyword allows you to configure a few options that relate to the
#   srchost, i.e., the host the Dante server accepts the connections from.
#   With the nodnsmismatch keyword, the server will not accept connections
#   from addresses having a mismatch between DNS IP address and hostname.
#   Default is to accept them.
#   With the nodnsunknown keyword, the server will not accept connections
#   from addresses without a DNS record. Default is to accept them.
#   With the checkreplyauth keyword, the server will check that the authentication
#   on bind-replies and udp-replies matches that which is set in the rule
#   and global socksmethod.
#   Normally, authentication is not desired on replies, as they are replies
#   sent to the socks-clients from non-socks clients, and thus only a limited
#   set of authentication methods are possible.
#   The methods possible for TCP are the the methods not involving the socks protocol
#   in any way, and are listed in the clientmethod section previously mentioned.
#   For UDP-replies, no methods can be used.
#   Default is not to check the authentication on replies.

# do you want to accept connections from addresses without
# dns info? what about addresses having a mismatch in dns info?
#srchost: nodnsunknown nodnsmismatch

###############################################################
##### SECTION 2 ##### SECTION 2 ##### SECTION 2 #########
############# Rules - Client First / Socks Second ############
###############################################################
#
# The actual rules. There are two kinds and they work at different levels.
#
# The rules prefixed with "client" are checked first and say who is allowed
# and who is not allowed to speak/connect to the server. I.e the
# ip range containing possibly valid clients.
# It is especially important that these only use IP addresses, not hostnames,
# for security reasons.
#
# The rules that do not have a "client" prefix are checked later, when the
# client has sent its request and are used to evaluate the actual
# request.
#
# The "to:" in the "client" context gives the address the connection
# is accepted on, i.e the address the socks server is listening on, or
# just "0.0.0.0/0" for any address the server is listening on.
#
# The "to:" in the non-"client" context gives the destination of the clients
# socks request.
#
# "from:" is the source address in both contexts.
#

#
# Logging Options for client and socks
#

# log: arg1 arg2 arg3 (one or more arguements)
#   connect - Information about accepted client connections
#   disconect - Information about disconnecting clients
#   ioop - Logging of each data transfer operation
#   data - Logging of the actual data transferred
#   tcpinfo - Logging of information obtained via the TCP_INFO socket option
#   error - Only in client rules - connection errors

#
# Several Items from sockd.conf MAN page
#

# libwrap
#   The server will pass the specified parameter line to libwrap for execution.
#   libwrap: spawn finger @%a

# port
#   Parameter to from, to and via. Accepts the keywords
#   eq/=, neq/!=, ge/>=, le/<=, gt/>, lt/< followed by a
#   number. A port range can also be given as "port <start #> - <end #>",
#   which will match all port numbers within the range <start #> and <end #>.
#   The default is to match all ports.
# command
#   The rule applies to the given commands. Valid commands are
#   bind, bindreply, connect, udpassociate and udpreply. Can be used
#   instead of, or to complement, protocol. The default is all commands
#   valid for the protocols allowed by the rule.
#
# NOTE: I typically allow command: bind connect - Unless you know for a
# certainty that your applications do not require bind or connect. Active
# FTP uses bind, but FTP should not be allowed in this day and age. Disallowing
# bind and connect may prevent SSH port forwarding. Not sure on this.
# If bind is enabled, then bindreply must also be enabled in one of the last rules.

# protocol
#   The rule applies to the given protocols. Valid values are tcp and udp.
#   The default is all supported protocols that can apply to the given commands.
#
# The "client" rules. All our clients come from the net 10.0.0.0/8.
#

# Allow our clients from: our networks port ALL PORTS to: INTERNAL IP of Dante Socks
# clientmethod: none - explicitly listing even though matches global value above
# log: Typically just error on this
# #log: commented out example for logging with ALL options
# #libwrap: - Commented out example on how to setup libwrap TCP Wrappers
# May need additional sections for additional from: networks
# Or to add different clientmethod or libwrap conditions
client pass {
   from: 9.0.0.0/8 port 1-65535 to: 192.168.1.105/32
   clientmethod: none
   #libwrap: spawn /usr/sbin/safe_finger @%a
   #log: connect disconnect ioop data error tcpinfo
   log: connect error
}

# drop everyone else as soon as we can and log the connect, they are not
# on our net and have no business connecting to us. This is the default
# but if you give the rule yourself, you can specify details.
client block {
   from: 0.0.0.0/0 to: 0.0.0.0/0
   log: connect error
}

#
# the rules controlling what clients are allowed what requests
#
# NOTE: The order of the rules is very important. Place the most
# restritive rules first followed by more permissive rules.
# The last rule should block everything else not explicitly
# allowed. SOCKS reads the rules line by line and the first
# match allows or denys a connection.

# you probably don't want people connecting to loopback addresses,
# who knows what could happen then.
socks block {
    from: 0.0.0.0/0 to: 127.0.0.0/8
    log: connect error
}

# Now we need to allow socks from our internal networks to our
# destination networks. The simple way to do this is to open all
# ports. But you can restrict access to certain boxes or networks to
# specific ports.

# From 9/8 to 10/8 (RFC 1918)
socks pass {
   from: 9.0.0.0/8 to: 10.0.0.0/8
   socksmethod: none
   command: bind connect
   log: connect error
}

# From 9/8 to 192.168.0.0/16 (RFC 1918)
socks pass {
   from: 9.0.0.0/8 to: 192.168.0.0/16
   socksmethod: none
   command: bind connect
   log: connect error
}

# From 9/8 to 172.16.0.0/12 (RFC 1918)
# Also includes commented out libwrap example
socks pass {
   from: 9.0.0.0/8 to: 172.16.0.0/12
   socksmethod: none
   #libwrap: spawn /usr/sbin/safe_finger @%a
   command: bind connect
   log: connect error
}

# Allow incoming replys to bind and udp connections
socks pass {
   from: 0.0.0.0/0 to: 9.0.0.0/8
   command: bindreply udpreply
   log: connect error
}

# last line, block everyone else. This is the default but if you provide
# one yourself you can specify your own logging/actions
socks block {
   from: 0.0.0.0/0 to: 0.0.0.0/0
   log: connect error
}

#
# EOF
#

Optional CPU real-time Scheduling and Traffic Monitoring

These sections are optional.  Refer to the official documentation for more information about these options.  I cannot get this to work on my Raspbian 8 PI.  I will be doing more PD in the future.

###############################################################
##### SECTION 3 ##### SECTION 3 ##### SECTION 3 #########
############# CPU Real Time Scheduling & CPU Affinity #########
###############################################################

# OPTIONAL - CPU Real Time Scheduling & CPU Affinity
# NOTE: MUST INSTALL schedtool fileset (Query and set CPU sched parms)
# Dante Process types
# Mother - Accepts connections from clients & forwards clients between
# other Dante process types
# Monitor - Monitors connection state and data rate
# Negotiate - Handles SOCKS protocol negotiation and performs first
# level ACL checks (client-rules)
# Request - Verifies the SOCKS request, performs second level ACL checks
# (socks-rules) and opens connections to target hosts
# IO - Handles the I/O (TCP, UDP, ICMP) between clients and targets
#
# cpu.schedule.PROCTYPE: SCHED/PRIORITY
# PROCTYPE - Dante process type (mother, monitor, negotiate, request, io)
# io type may have impact on performance
# SCHED - Real-time sched algorithm (fifo, rr, other) Note 'other' is the
# standard, non-realtime scheduling algorithm
# PRIORITY - A numeric value giving the process' scheduling priority
#
# Set real-time scheduling (round-robin):
#cpu.schedule.mother: rr/10
#cpu.schedule.negotiate: rr/10
#cpu.schedule.request: rr/10
#cpu.schedule.io: rr/15

# CPU Affinity
# Specify which CPU different Dante process should use. May ensure one CPU
# available for non-Dante work to prevent Dante from consuming all resources.
#
# cpu.mask.PROCTYPE: CPUIDS
#
# PROCTYPE - Dante process type (mother, monitor, negotiate, request, io)
# CPUIDS - A space-separated list of CPUs to which process of specfied type
# should bind
#
# The following example assumes 4 CPUs (0-3)
# Run io process on CPUs 1+2, all other Dante process on CPU 3
# CPU 0 is free for other non-Dante related tasks
#cpu.mask.mother: 3
#cpu.mask.monitor: 3
#cpu.mask.negotiate: 3
#cpu.mask.request: 3
#cpu.mask.io: 1 2

###############################################################
##### SECTION 4 ##### SECTION 4 ##### SECTION 4 #########
############# Traffic Monitoring ##############################
###############################################################

# OPTIONAL
# Traffic monitoring is now included with Dante
# Dante will only perform passive monitoring of network traffic or the lack
# of network traffic. At this time only TCP monitoring should be performed.
# from - normally specifies what client addresses/networks to monitor
# to - normally specifies what target addresses/networks to monitor
# protocol - TCP should be used for now
# hostid - can be used to restrict monitoring to only clients with
# specific hostid
# hostindex - used along with hostid to control which of 2 possible
# hostid values will be used when matching
#
# Data Idleness Detection
# internal.alarm.data.recv - data received on internal interface -
# data sent from SOCKS client to Dante
# internal.alarm.data.send - data sent out internal interface -
# data sent from Dante to SOCKS clients
# external.alarm.data.recv - data received on external interface -
# data sent from target servers to Dante
# external.alarm.data.send - data sent out external interface -
# data sent from Dante to target servers
# Each alarm above takes 2 parameters (DATALIMIT in INTERVAL)
# DATALIMIT - number that specifies the byte limit
# INTERVAL - number that specifies the duration
# internal.alarm.data.recv: 0 in 10
# Alarm if no data is received by Dante for period of 10 seconds.
# Multiple monitors may be combined
#monitor {
# from: 0.0.0.0/0 to: 0.0.0.0/0
# protocol: tcp
# internal.alarm.data.recv: 0 in 90
# external.alarm.date.send: 10240 in 300
#}

# Abnormal Rate of Connection Termination Detection
# If large number of connections are terminated with a short period
# of time, this is possibly an indication of connectivity or network
# problems. Perhaps due to a remote network server/proxy crashing.
#
# internal.alarm.disconnect - Connections between clients and Dante server.
# external.alarm.disconnect - Connections between Dante server and target
#
# internal.alarm.disconnect: MINCOUNT/RATIO in INTERVAL
# MINCOUNT - Minimum number of connections that must be disconnected for
# the alarm to trigger
# RATIO - used together with MINCOUNT to express number of connections,
# relative to the total number of connections that have existed
# in the time period, that must be disconnected for the alarm to
# trigger. To trigger alarm if HALF active connections during a
# time interval.
# example - 200/400
# INTERVAL - Time in seconds within which the disconnect must occur for
# the alarm to trigger.
#
#
#monitor {
# from: 0.0.0.0/0 to: 0.0.0.0/0
# protocol: tcp
# # warm if 1/3 or more sessions disconnect during period of 5 seconds
# # but require a minimum of 1000 disconnects on either side
# internal.alarm.disconnect: 1000/3000 in 5
# external.alarm.disconnect: 1000/3000 in 5
#}

#
# EOF
#

Compiled Version and Sample Files

The attached file has the compiled version of Dante Socks v1.4.1 for Raspbian 8 Wheezy.  Plus it contains the sockd.conf file and the sockd.service file.

Contents of dante-1.4.1-raspbian-8-wheezy.tar.gz

/etc/sockd/
/etc/sockd/sockd.conf.b4-edit
/usr/local/sockd/
/usr/local/sockd/lib/
/usr/local/sockd/lib/libsocks.so.0
/usr/local/sockd/lib/libdsocks.la
/usr/local/sockd/lib/libsocks.a
/usr/local/sockd/lib/libdsocks.so
/usr/local/sockd/lib/libsocks.so
/usr/local/sockd/lib/libsocks.la
/usr/local/sockd/lib/libsocks.so.0.1.1
/usr/local/sockd/share/
/usr/local/sockd/share/man/
/usr/local/sockd/share/man/man1/
/usr/local/sockd/share/man/man1/socksify.1
/usr/local/sockd/share/man/man8/
/usr/local/sockd/share/man/man8/sockd.8
/usr/local/sockd/share/man/man5/
/usr/local/sockd/share/man/man5/sockd.conf.5
/usr/local/sockd/share/man/man5/socks.conf.5
/usr/local/sockd/bin/
/usr/local/sockd/bin/socksify
/usr/local/sockd/sbin/
/usr/local/sockd/sbin/sockd
/usr/local/sockd/include/
/usr/local/sockd/include/socks.h
/etc/systemd/system/sockd.service

Compiling Dante Socks v1.4.1

Dante Socks

I have been using Dante Socks for many years now.  It is quite easy to compile.  Although it is probably easier in may respects to simply use a dynamic SSH proxy.  For more information about Dante Socks use the URL below.

http://www.inet.no/dante/

I will be adding a configuration file with comments in another post.  And my goal is to configure Dante Socks to run under systemd.  I need to create a new service unit.  And I want to see how well journald logs.  This will be in separate posts once I have had time to experiment and test.

A Note on Security

As noted on the Dante site, socks does not encrypt your connection, with the exception of compiling in kerberos as an option (gssapi).  It should not be used on an open network.  I have used TACACS+ in the past to login into the Dante Socks server before being able to tunnel my connections.  And that at least will encrypt your ID and password.  Just keep in mind the data will still be unencrypted.  Of course if you are using SSH those packets are secure.  Someone could open the encapsulated packet but then they could not open the encrypted SSH packet within.

Compiling Options

Run './configure --help' for more options.  But to add libwrap (TCP Wrappers), PAM, and gssapi (Kerberos) you need to install the correct headers package first.  The following list is for Raspian 8.  Refer to the official documentation for more information.

  • libwrap0-dev - Headers for librwap
  • libpam0g-dev - Headers for PAM
  • libkrb5-dev - Headers for kerberos

The first time I used socks the binary was located in '/usr/local/sockd/sbin/sockd'.  And the configuration file was in '/etc/sockd/sockd.conf'.  I still compile socks to use these directories.  This of course is completely optional.

  • --prefix=/usr/local/sockd
  • --with-sockd-conf=/etc/sockd/sockd.conf

There is one more optional flag.  If you do not need the client libraries you can add the flag below.  The socksify client will still compile, but the lib directory and the libraries will not be compiled.

  • --disable-client

Listing of the Libraries:

  • libdsocks.la - Textual file that includes a description of the library.  It allows libtool to create platform independant names.
  • libdsocks.so - Shared library which does 'on the fly' socksification.
  • libsocks.la
  • libsocks.so - Shared library - Contains the Rfoo type functions
  • libsocks.a - Static version of libsocks.so

Compile the Code

As stated elsewhere in my posts I came from a mixed UNIX family.  I worked a lot with AIX.  But I also did a lot of work with RHEL, HP-UX and Solaris.  As a result I tend to use commands that work on all platforms.  I know my gzip command below can be simplified with GNU tar.  But that wasn't available on AIX at that time.  Download the code from the URL above.  Place it in '/tmp'.  (/tmp/dante-1.4.1.tar.gz)  Switch to your source directory.  And perform the following steps to compile the code.

  • cd /usr/src
  • umask 022
  • gzip -dc /tmp/dante-1.4.1.tar.gz | tar xvf -
  • cd /usr/src/dante-1.4.1
  • ./configure --prefix=/usr/local/sockd \
    --with-sockd-conf=/etc/sockd/sockd.conf
  • make
  • make install
  • ls -lR /usr/local/sockd (To confirm the existence of the binaries.)
  • [OPTIONAL] strip /usr/local/sockd/sbin/sockd
  • [OPTIONAL] strip /usr/local/sockd/bin/socksify
  • mkdir -m 0755 /etc/sockd
  • cp -p example/sockd.conf /etc/sockd/sockd.conf
  • tar -cvfP - /etc/sockd /usr/local/sockd |gzip >dante-1.4.1-PI.tgz

The '/usr/src/dante-1.4.1/example/sockd.conf' file is a good place to start configuring your Dante socks server.  As stated above I plan to test out some new features of Dante 1.4.1 and post a sample sockd.conf file in the near future.

NOTE:  You must create an INIT script.  This can be either for SysV or systemd init.  If Dante is configured to log to a file the user must also create a log rotation script.  See the Dante FAQ for more information.

Displaying the MAN Pages

There will be four MAN pages.  One for the socksify client.  One for the socksify client configuration (socks.conf).  One for the socks server (sockd).  And one for the socks server configuration (sockd.conf).  You need to update your '/etc/manpath.config' file or use the -M flag with man to read the MAN pages.

  • socksify = man -M/usr/local/sockd/share/man socksify
  • socksify config = man -M/usr/local/sockd/share/man socks.conf
  • sockd = man -M/usr/local/sockd/share/man sockd
  • sockd config = man -M/usr/local/sockd/share/man sockd.conf

Xauth, X11, & Magic Cookies

X11 Forwarding

Fortunately X11 applications are rather rare these days.  Most applications use HTML for the GUI.  However, at times X11 may be required.  And if you need to SUDO to another ID it is possible to lose your magic cookie.  Personally, I would install VNC and forward that over SSH.  But if you must use X11 here is a quick way to set it up and use xauth to get the DISPLAY variable set properly.

Enable X11 Forwarding on the Server

I prefer to forward my X11 DISPLAY to localhost.  These directions assume X11 will use localhost.  Adjust these directions as appropriate if you cannot use localhost.  First on the server update '/etc/ssh/sshd_config' and set the three variables shown below.  Make sure you restart SSHD or reboot the server afterwards.

  • X11Forwarding yes
  • X11DisplayOffset 10
  • X11UseLocalHost yes

Setup the X11 Server on the Client

On a Windows box install an X11 server such as Cygwin, Xming, X-Win32, Exceed or some other X11 server for Windows.  In your SSH client make sure you enable X11 forwarding for this connection.  This can be done easily in PuTTY, SecureCRT, or the Cygwin command prompt (ssh -XY user@x.x.x.x).  These directions assume you already know how to configure your client to forward X11 packets.  I have used all of these methods and servers in the past connecting to AIX and RHEL servers.  In this example I will use Cygwin since it is free, although it is my least favorite.  I have a love hate relationship with Cygwin.  I am connecting to a Raspberry PI running Raspbian Jessie.

The Key File - ~/.Xauthority

When you SSH to a box with X11 forwarding enabled the 'xauth' command will setup your magic cookie in your home directory in the '.Xauthority' file.  This file consists of three values.  To display the contents of this file run 'xauth list'.  We are using 'MIT-MAGIC-COOKIE-1' as the protocol in our X11 sessions.

The .Xauthority file will consist of three values.

  • DisplayName  ProtocolName  Hexkey

The proper permissions for the .Xauthority file.  The file should be owned by your UID and GID and have the permissions set to 0600.

$ ls -la ~/.Xauthority
-rw------- 1 pi pi 180 Jun 15 22:32 /home/pi/.Xauthority

Display the contents with the 'xauth list' command.  The bold blue number in the display name section is the key number we need to identify.

$ xauth list
pi1.zaphod.local/unix:10 MIT-MAGIC-COOKIE-1 a57c1e1cea874b8dd002b82cf7c0fb34
pi1.zaphod.local/unix:11 MIT-MAGIC-COOKIE-1 6ba1e0d9cc5de492cc4af43b4f0faa20

Step by Step Using Cygwin

This example will use Cygwin to setup our GUI as the 'pi' user and as root.  These directions assume you will run 'sudo su - <ID>' to switch to another user and use the shell of the new user.

  • Launch the Cygwin terminal
  • startx & (This will launch the X11 server in the background.)
  • Minimize the X11 screen and return to the Cygwin terminal
  • Run "export DISPLAY=:0:0" without the quotes.  This just ensures the DISPLAY is properly exported on the server.  This step is only required in Cygwin.  I actually don't remember having to do this in the past.  You could also simply export your DISPLAY on the server.  (export DISPLAY=localhost:0.0)
  • SSH to your server.  Update with the proper ID and IP address or hostname.  ssh -XY pi@192.168.1.101
  • If this is your first time connecting a new .Xauthority file will be created.  It is a good idea to check for the existence of this file whenever you need to use X11.
  • Verify your DISPLAY has been set by running 'echo $DISPLAY' without the quotes.  And identify your DISPLAY number.  In this example it is '11'.

$ echo $DISPLAY
localhost:11.0

  • You can run 'xterm' to quickly verify X11 is being properly forwarded.  Exit the 'xterm' window in the Cygwin GUI.
  • Now identify your X11 session in 'xauth list'.  If you have more than one line, find the line that has the same session number when you run 'echo $DISPLAY' as shown above.  In this example, we have two lines.  The second line is our current X11 session.  It is session number '11'.

$ xauth list
pi1.zaphod.local/unix:10 MIT-MAGIC-COOKIE-1 a57c1e1cea874b8dd002b82cf7c0fb34
pi1.zaphod.local/unix:11 MIT-MAGIC-COOKIE-1 2beda25c5b32ab9630a619b5705690c3

  • Switch to your new user with a new shell.  In this example I am switching to root.  (sudo su -)
  • Verify your DISPLAY by running 'echo $DISPLAY'.  It may or may not be set correctly to match your previous session.  Run 'xauth list' and if this is the first time you have connected you will not have a '~/.Xauthority' file.  Regardless if $DISPLAY is set properly or not, we should add our magic cookie from our previous session.  This will ensure X11 functions properly.

$ sudo su -
root@pi1:~# echo $DISPLAY
localhost:11.0
root@pi1:~# xauth list
xauth: file /root/.Xauthority does not exist

  • Add the magic cookie by copying the '11' line from your '.Xauthority' file and adding it to the new user ID by running 'xauth add <xauthority_line>'.  See the example below.  I escaped the command to make it more legible.

# xauth add \
>pi1.zaphod.local/unix:11 MIT-MAGIC-COOKIE-1 2beda25c5b32ab9630a619b5705690c3
xauth: file /root/.Xauthority does not exist

  • The first time you run this command you will get the error above.  The file is created by xauth.  Simply run 'xauth list' to verify the contents.  And it should match.

# xauth list
pi1.zaphod.local/unix:11 MIT-MAGIC-COOKIE-1 2beda25c5b32ab9630a619b5705690c3

  • And VOILA!  You can now run your GUI.  And you can complain to the manufacturer and tell them to convert to HTML.  Or better yet, use VNC server instead of X11.  This also allows you to disconnect your session and go home and reconnect to the same X11 session.

Fix MAN Page Formatting

Locale Definition

RHEL defines locale as follows.  The system locale specifies the language settings of the system services and user interfaces.  The keyboard layout settings control the layout used on the text console and graphical user interfaces.  ArchLinux defines locale as follows.  Locales are used by glibc and other locale-aware programs or libraries for rendering text, correctly displaying regional monetary values, time and date formats, alphabetic idiosyncrasies, and other locale-specific standards.

Different versions of UNIX set the locale variables in different manners.  Refer to the official documentation for your OS to find the proper way to set the locale variables.  Also different OS'es will use different commands to display and set locale variables.

Various Locale Settings

This list may vary from OS to OS.

  • LANG - Provides a default value for the system locale
  • LC_COLLATE - Changes the behavior of functions which compare strings in the local alphabet.
  • LC_CTYPE - Change the behavior of the character handling and classification functions and the multibyte character functions.
  • LC_NUMERIC - Describes the way numbers are usually printed, with details such as decimal point versus decimal comma.
  • LC_TIME - Changes the display of the current time, 24-hour versus 12-hour clock.
  • LC_MESSAGES - Determines the locale used for diagnostic messages written to the standard error output.
  • LC_ADDRESS - Convention used for formatting of street or postal addresses.
  • LC_MONETARY - Monetary formatting
  • LC_MEASUREMENT - Default measurement system used within the region.
  • LC_PAPER - Default paper size for region
  • LC_RESPONSE - Determines how responses (such as Yes and No) appear in the local language.
  • LC_TELEPHONE - Conventions used for representation of telephone numbers.
  • LC_ALL - High precedence override for locale specific behavior (overrides all other locale variables)

MAN Page Formatting

At times when you read a man page you may have odd characters.  To fix this you need to set 'LC_ALL' to C.  There are two ways to set this variable.

  • command line = export LC_ALL=C
  • ~/.bashrc = export LC_ALL=C

TCPDUMP

Checking Flows with TCPDUMP

This is a brief rundown on how to use TCPDUMP to verify flows between boxes.  This should be done before calling the network team for help on something that isn't working.  Different OS'es may have different flags.  Always refer to the manpage for your version of TCPDUMP.

Verifying that packets are reaching another box before calling the network team is always a good thing.  And it is quite simple to verify that packets are leaving on the correct interface and port.

Other Sites and References

The following sites contain a lot of useful information.  And they contain far more detailed explanations of how to use tcpdump.  My little document is just a brief reminder for myself of some of the very basics.

http://www.tcpdump.org/manpages/tcpdump.1.html

Wikipedia Article on TCP - Check out the TCP Headers Section

Very Nice Site with Detailed Explanation on How to Use tcpdump

Another Nice Site on Using tcpdump

Nice Site to Explain the Output in Greater Detail

Flags

On Linux the following flags are most often used.

  • tcpdump -lnp -i ent0
    • -l (Lowercase L) - Make stdout line buffered.  This allows you to see the data while it is being captured.
    • -n - Don't convert host addresses to names.  Show the IP Address
    • -p - Do NOT put interface into promiscuous mode.  Since we are not on a router or have a real sniffer we can reduce the amount of traffic.
    • -i <Interface> - Listen on this interface
  • Other useful flags
    • -t - Don't print the timestamp
    • -nn - Don't convert protocol and port numbers into names
    • -q - Print less protocol information to make the lines shorter
    • -A - Print each packet (minus its link level header) in ASCII.  Useful to capture web pages or IDs and Passwords in clear text.

Filters

The proper use of filters will allow us to find the packet information we need quickly and accurately.  And it will dramatically reduce the amount of traffic we need to parse.

tcpdump -lnp -i ent0 <PROTOCOL> <DIRECTION> <TYPE>

  • Protocol = IP, tcp, udp, icmp, arp, rarp, stp (spanning tree protocol), and ether
  • Direction = src (source), dst (destination), src or dst, & src and dst
  • Type = net (CIDR (10.2.1.0/24) or leave off .octet (192.168.1)), host (IP address or hostname), port (Number (512) or name (syslog))

To combine various filters use the following operands.

  • && = and
  • || = or
  • ! = not

Reading the Output

I am not a network guy.  But I have a basic understanding.  A few google searches should help answer any questions about the output of tcpdump.  The basic format of the output is shown below.

timestamp.sequence protocol source.port > destination.port : Flags[S] 

23:37:27.538449 IP 192.168.1.101.53592 > 172.217.4.100.443: Flags [S], seq 3355934968, win 29200, options [mss 1460,sackOK,TS val 18945927 ecr 0,nop,wscale 7], length 0
23:37:27.556056 IP 172.217.4.100.443 > 192.168.1.101.53592: Flags [S.], seq 4030977753, ack 3355934969, win 42540, options [mss 1430,sackOK,TS val 2246473456 ecr 18945927,nop,wscale 7], length 0
23:37:27.556138 IP 192.168.1.101.53592 > 172.217.4.100.443: Flags [.], ack 1, win 229, options [nop,nop,TS val 18945929 ecr 2246473456], length 0

23:37:27.662155 IP 192.168.1.101.53592 > 172.217.4.100.443: Flags [P.], seq 1:278, ack 1, win 229, options [nop,nop,TS val 18945940 ecr 2246473456], length 277

Flags:

  • [S] = SYN
  • [.] = No Flag Set
  • [P] = PSH (Push Data)
  • [F] = FIN (Finish Connection)
  • [R] = RST (Reset Connection)
  • [S.] = SYN-ACK

ACK <NUMBER> = The TCP packet's acknowledgement number

WIN <NUMBER> = The source host's TCP window.

LENGTH <NUMBER> = The TCP packet length in bytes including headers.

A Few Examples

To find the available interfaces run the following command.

# tcpdump -D

The first example shows the results from a dig query on pahoehoe.net with a +trace.  It has been edited to reduce the total number of lines.

# tcpdump -i wlan0 -lnpt udp && port 53
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 192.168.1.101.39991 > 8.8.8.8.53: 28569+ A? a.root-servers.net. (36)
IP 192.168.1.101.39991 > 8.8.8.8.53: 40484+ AAAA? a.root-servers.net. (36)
IP 8.8.8.8.53 > 192.168.1.101.39991: 28569 1/0/0 A 198.41.0.4 (52)
IP 8.8.8.8.53 > 192.168.1.101.39991: 40484 1/0/0 AAAA 2001:503:ba3e::2:30 (64)
IP 192.168.1.101.46308 > 198.41.0.4.53: 52876 [1au] NS? . (28) (A root)
IP 198.41.0.4.53 > 192.168.1.101.46308: 52876*- 14/0/25 NS e.root-servers.net., NS h.root-servers.net., NS l.root-servers.net., NS i.root-servers.net., NS a.root-servers.net., NS d.root-servers.net., NS c.root-servers.net., NS b.root-servers.net., NS j.root-servers.net., NS k.root-servers.net., NS g.root-servers.net., NS m.root-servers.net., NS f.root-servers.net., RRSIG (913)
IP 192.168.1.101.42501 > 8.8.8.8.53: 33974+ A? e.root-servers.net. (36)
IP 192.168.1.101.42501 > 8.8.8.8.53: 49502+ AAAA? e.root-servers.net. (36)
.......
IP 192.168.1.101.47892 > 8.8.8.8.53: 27946+ AAAA? k.root-servers.net. (36)
IP 8.8.8.8.53 > 192.168.1.101.47892: 42746 1/0/0 A 193.0.14.129 (52)
IP 8.8.8.8.53 > 192.168.1.101.47892: 27946 1/0/0 AAAA 2001:7fd::1 (64)
IP 192.168.1.101.59375 > 8.8.8.8.53: 31188+ A? g.root-servers.net. (36)
IP 192.168.1.101.59375 > 8.8.8.8.53: 36734+ AAAA? g.root-servers.net. (36)
IP 8.8.8.8.53 > 192.168.1.101.59375: 31188 1/0/0 A 192.112.36.4 (52)
IP 8.8.8.8.53 > 192.168.1.101.59375: 36734 0/1/0 (96)
IP 192.168.1.101.53501 > 8.8.8.8.53: 696+ A? m.root-servers.net. (36)
IP 192.168.1.101.53501 > 8.8.8.8.53: 32497+ AAAA? m.root-servers.net. (36)
IP 8.8.8.8.53 > 192.168.1.101.53501: 696 1/0/0 A 202.12.27.33 (52)
.........
IP 8.8.8.8.53 > 192.168.1.101.56152: 31995 1/0/0 A 192.31.80.30 (52)
IP 8.8.8.8.53 > 192.168.1.101.56152: 58905 0/1/0 (104)
IP 192.168.1.101.35845 > 8.8.8.8.53: 54527+ A? c.gtld-servers.net. (36)
IP 192.168.1.101.35845 > 8.8.8.8.53: 52197+ AAAA? c.gtld-servers.net. (36)
IP 8.8.8.8.53 > 192.168.1.101.35845: 54527 1/0/0 A 192.26.92.30 (52)
IP 8.8.8.8.53 > 192.168.1.101.35845: 52197 0/1/0 (104)
........
IP 8.8.8.8.53 > 192.168.1.101.44186: 26320 1/0/0 A 192.41.162.30 (52)
IP 8.8.8.8.53 > 192.168.1.101.44186: 37854 0/1/0 (104)
IP 192.168.1.101.53102 > 192.5.6.30.53: 15697 [1au] A? pahoehoe.net. (41) (Query A GTLD Server - With Response Below)
IP 192.5.6.30.53 > 192.168.1.101.53102: 15697- 0/6/3 (603)
IP 192.168.1.101.58902 > 8.8.8.8.53: 13390+ A? ns1.hover.com. (31)
IP 192.168.1.101.58902 > 8.8.8.8.53: 58557+ AAAA? ns1.hover.com. (31)
IP 8.8.8.8.53 > 192.168.1.101.58902: 13390 1/0/0 A 216.40.47.26 (47)
IP 8.8.8.8.53 > 192.168.1.101.58902: 58557 0/1/0 (77)
IP 192.168.1.101.42884 > 8.8.8.8.53: 26535+ A? ns2.hover.com. (31)
IP 192.168.1.101.42884 > 8.8.8.8.53: 62352+ AAAA? ns2.hover.com. (31)
IP 8.8.8.8.53 > 192.168.1.101.42884: 26535 1/0/0 A 64.98.148.13 (47)
IP 8.8.8.8.53 > 192.168.1.101.42884: 62352 0/1/0 (81)
IP 192.168.1.101.51286 > 216.40.47.26.53: 58438 [1au] A? pahoehoe.net. (41)
IP 216.40.47.26.53 > 192.168.1.101.51286: 58438*- 1/0/0 A 173.236.174.31 (46) (NS1.HOVER.COM Responds with A Record)

Checking ICMP echo-request and echo-reply to 8.8.8.8.  Check the Wikipedia article for more ICMP control messages.

# tcpdump -lnp -i wlan0 icmp and net 8.8.8.0/24
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes
04:36:43.910160 IP 192.168.1.101 > 8.8.8.8: ICMP echo request, id 24772, seq 1, length 64
04:36:43.939672 IP 8.8.8.8 > 192.168.1.101: ICMP echo reply, id 24772, seq 1, length 64
04:36:44.912043 IP 192.168.1.101 > 8.8.8.8: ICMP echo request, id 24772, seq 2, length 64
04:36:44.937692 IP 8.8.8.8 > 192.168.1.101: ICMP echo reply, id 24772, seq 2, length 64

You can grab plain text ID and passwords using the '-A' flag.  This also shows the port option.  You can use the port number of the common name.

# tcpdump -lnpA -i wlan0 port ftp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes
04:55:04.944303 IP 192.168.1.101.45514 > 198.57.170.33.21: Flags [S], seq 902807131, win 29200, options [mss 1460,sackOK,TS val 37261499 ecr 0,nop,wscale 7], length 0
E..<..@.@..s...e.9.!....5..[......r.j..........
.8..........
.......
E..t..@.3.<V.9.!...e....R[..5..\...........
.jV".8..220---------- Welcome to Pure-FTPd [privsep] [TLS] ----------
220-You are user number 2 of 50 allowed.
220-Local time is now 23:55. Server port: 21.
220-This is a private system - No anonymous login
220-IPv6 connections are also welcome on this server.
220 You will be disconnected after 15 minutes of inactivity.

04:55:05.042076 IP 192.168.1.101.45514 > 198.57.170.33.21: Flags [.], ack 321, win 237, options [nop,nop,TS val 37261508 ecr 3295303202], length 0
E..4..@.@..i...e.9.!....5..\R[.$.....S.....
.8...jV"
04:55:07.082735 IP 192.168.1.101.45514 > 198.57.170.33.21: Flags [P.], seq 1:12, ack 321, win 237, options [nop,nop,TS val 37261713 ecr 3295303202], length 11
E..?..@.@..]...e.9.!....5..\R[.$....w......
.8...jV"USER anon

04:55:07.133890 IP 198.57.170.33.21 > 192.168.1.101.45514: Flags [.], ack 12, win 46, options [nop,nop,TS val 3295305290 ecr 37261713], length 0
E..4..@.3.=..9.!...e....R[.$5..g...........
.j^J.8..
04:55:07.133910 IP 198.57.170.33.21 > 192.168.1.101.45514: Flags [P.], seq 321:358, ack 12, win 46, options [nop,nop,TS val 3295305290 ecr 37261713], length 37
E..Y..@.3.=o.9.!...e....R[.$5..g...........
.j^J.8..331 User anon OK. Password required
04:55:09.854433 IP 192.168.1.101.45514 > 198.57.170.33.21: Flags [P.], seq 12:27, ack 358, win 237, options [nop,nop,TS val 37261990 ecr 3295305290], length 15
E..C..@.@..W...e.9.!....5..gR[.I...........
.8...j^JPASS password
04:55:14.115825 IP 198.57.170.33.21 > 192.168.1.101.45514: Flags [P.], seq 358:391, ack 27, win 46, options [nop,nop,TS val 3295312272 ecr 37261990], length 33
E..U..@.3.=q.9.!...e....R[.I5..v...........
.jy..8..530 Login authentication failed

Show the packets to and from host 216.58.192.196.  The timestamps have been removed to reduce the clutter.

# tcpdump -i wlan0 -lnpt host 216.58.192.196
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 192.168.1.101.50207 > 216.58.192.196.443: Flags [S], seq 910478434, win 29200, options [mss 1460,sackOK,TS val 18694987 ecr 0,nop,wscale 7], length 0
IP 216.58.192.196.443 > 192.168.1.101.50207: Flags [S.], seq 2406340571, ack 910478435, win 42540, options [mss 1430,sackOK,TS val 35546692 ecr 18694987,nop,wscale 7], length 0
IP 192.168.1.101.50207 > 216.58.192.196.443: Flags [.], ack 1, win 229, options [nop,nop,TS val 18694989 ecr 35546692], length 0
IP 192.168.1.101.50207 > 216.58.192.196.443: Flags [P.], seq 1:278, ack 1, win 229, options [nop,nop,TS val 18695004 ecr 35546692], length 277
IP 216.58.192.196.443 > 192.168.1.101.50207: Flags [.], ack 278, win 341, options [nop,nop,TS val 35546861 ecr 18695004], length 0
IP 216.58.192.196.443 > 192.168.1.101.50207: Flags [.], seq 1:1419, ack 278, win 341, options [nop,nop,TS val 35546863 ecr 18695004], length 1418
IP 216.58.192.196.443 > 192.168.1.101.50207: Flags [.], seq 1419:2837, ack 278, win 341, options [nop,nop,TS val 35546863 ecr 18695004], length 1418
IP 216.58.192.196.443 > 192.168.1.101.50207: Flags [P.], seq 2837:3502, ack 278, win 341, options [nop,nop,TS val 35546863 ecr 18695004], length 665
IP 192.168.1.101.50207 > 216.58.192.196.443: Flags [.], ack 1419, win 251, options [nop,nop,TS val 18695006 ecr 35546863], length 0
IP 192.168.1.101.50207 > 216.58.192.196.443: Flags [.], ack 2837, win 274, options [nop,nop,TS val 18695006 ecr 35546863], length 0
IP 192.168.1.101.50207 > 216.58.192.196.443: Flags [.], ack 3502, win 296, options [nop,nop,TS val 18695006 ecr 35546863], length 0
IP 192.168.1.101.50207 > 216.58.192.196.443: Flags [P.], seq 278:404, ack 3502, win 296, options [nop,nop,TS val 18695008 ecr 35546863], length 126
IP 216.58.192.196.443 > 192.168.1.101.50207: Flags [P.], seq 3502:3748, ack 404, win 341, options [nop,nop,TS val 35546904 ecr 18695008], length 246
IP 192.168.1.101.50207 > 216.58.192.196.443: Flags [P.], seq 404:691, ack 3748, win 319, options [nop,nop,TS val 18695012 ecr 35546904], length 287
IP 216.58.192.196.443 > 192.168.1.101.50207: Flags [P.], seq 3748:5166, ack 691, win 350, options [nop,nop,TS val 35546976 ecr 18695012], length 1418
IP 216.58.192.196.443 > 192.168.1.101.50207: Flags [P.], seq 5166:6543, ack 691, win 350, options [nop,nop,TS val 35546976 ecr 18695012], length 1377
IP 216.58.192.196.443 > 192.168.1.101.50207: Flags [F.], seq 6543, ack 691, win 350, options [nop,nop,TS val 35546976 ecr 18695012], length 0
IP 192.168.1.101.50207 > 216.58.192.196.443: Flags [.], ack 6543, win 364, options [nop,nop,TS val 18695017 ecr 35546976], length 0
IP 192.168.1.101.50207 > 216.58.192.196.443: Flags [.], ack 6544, win 364, options [nop,nop,TS val 18695021 ecr 35546976], length 0
IP 192.168.1.101.50207 > 216.58.192.196.443: Flags [F.], seq 691, ack 6544, win 364, options [nop,nop,TS val 18695465 ecr 35546976], length 0
IP 216.58.192.196.443 > 192.168.1.101.50207: Flags [.], ack 692, win 350, options [nop,nop,TS val 35551466 ecr 18695465], length 0

Check packets from source host.  You can use 'src net 1.2.3.0/24' as well.  Of course you can add other filters to search for a port or something else.

# tcpdump -i wlan0 -lnpt src 192.168.1.101
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on wlan0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 192.168.1.101.22 > 192.168.1.2.52638: Flags [P.], seq 3964313467:3964313707, ack 2205964022, win 350, length 240
IP 192.168.1.101.22 > 192.168.1.2.52638: Flags [P.], seq 240:448, ack 1, win 350, length 208
IP 192.168.1.101.22 > 192.168.1.2.52638: Flags [P.], seq 448:624, ack 1, win 350, length 176
IP 192.168.1.101.22 > 192.168.1.2.52638: Flags [P.], seq 624:800, ack 1, win 350, length 176
IP 192.168.1.101.22 > 192.168.1.2.52638: Flags [P.], seq 800:976, ack 1, win 350, length 176
IP 192.168.1.101.22 > 192.168.1.2.52638: Flags [P.], seq 976:1152, ack 1, win 350, length 176
IP 192.168.1.101.22 > 192.168.1.2.52638: Flags [P.], seq 1152:1344, ack 1, win 350, length 192
IP 192.168.1.101.22 > 192.168.1.2.52638: Flags [P.], seq 1344:1536, ack 1, win 350, length 192

DIG (Domain Information Groper)

The Basics of DIG

The following examples explain how to use DIG to query various name servers on the internet or on an intranet.  This is just a brief rundown of various commands that are easily forgotten if not used often.  A few nslookup commands will also be included as a reference in case someone is forced to use that deprecated command.  There are numerous sites that explain in great detail each option.  This page is a quick reference for myself for a lot of the common examples.  Keep in mind each time BIND is updated there may be new flags or deprecated flags in DIG.

I tend to specify a specific name server to use by including the "@ns" flag.  When doing PD work it is best to query the authoritative name server and travel down the hierarchy.  Start with '@[a-m].root-servers.net'.

A Few Definitions

  • ROOT ZONE - DNS is hierarchical.  The very top is the root zone which is represented by a single "." (DOT).  The root name servers ([a-m].root-servers.net.) are authoritative for ".".  Delegation then flows to the various global top level domain servers for '.edu.', '.com.', '.net.' etc.
  • Forward Resolution - Converting domain names into IP addresses. (google.com == 216.58.216.206) (The result is the A record)
  • A - In a zone file (db.google) the A record points to the IP Adress (hostname IN A w.x.y.z)
  • AAAA - Quad A for IPv6 records
  • Reverse Resolution - Converting IP addresses into domain names.  (216.58.216.206 == google.com)  (The result is the PTR record.)
  • PTR - In a zone file (db.216.58.216) the PTR records points to the FQDN (Fully Qualified Domain Name) with the DOT at the very end. (last_octet IN PTR host.example.com. )
  • NS = Name Server
  • MX = Mail Exchange
  • SOA = Start of Authority (Includes the following)
    • TTL for the zone - Time to Live - duration zone may be cached by any resolver
    • Class of the record - Typically it is "IN" for internet class.  Other less likely candidates are "CH" for chaos or "HS" for hesiod.
    • Authoritative Name Server (NS)
    • Email address for admin for the domain
    • Timestamp that changes with every update (aka serial number - YYYYMMDDII)
    • Refresh (3H) - Indicates the time the slave will try to refresh the zone from the master.
    • Retry (1H) - Defines the time between retries if the slave fails to contact the master when the refresh has expired.  (Or a NOTIFY message is received.)
    • Expiry (1W) - Indicates when the zone data is no longer authoritative by the slave server if it cannot contact the master.
    • Negative TTL (1H) (NXDOMAIN TTL) - The time any resolver may cache any NXDOMAIN result.  Non-existent domain
  • Recursion - Name resolution technique where a name server queries other name servers on behalf of the requesting client and then sends the answer back.  In other words a recursive server will query the root servers and travel down all of the DNS hierarchy to find the answer for the client.  Typically not a good thing for internet facing DNS servers as this service may be abused by miscreants.

DIG Syntax

The basic usage example is as follows.

Usage: dig [@global-server] [domain] [q-type] [q-class] {q-opt}
           {global-d-opt} host [@local-server] {local-d-opt}
           [ host [@local-server] {local-d-opt} [...]]

Understanding the Basic Output

Below are the results of the query 'dig @8.8.8.8 isc.org'.  Following that each section of the answer is explained in more detail.

# dig @8.8.8.8 isc.org

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @8.8.8.8 isc.org
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50815
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;isc.org. IN A

;; ANSWER SECTION:
isc.org. 59 IN A 149.20.64.69

;; Query time: 107 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sun Jun 05 06:47:57 UTC 2016
;; MSG SIZE rcvd: 52


The first three lines show the DIG version and the query.  These lines may be suppressed with the '+nocmd' flag.

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @8.8.8.8 isc.org
; (1 server found)
;; global options: +cmd

The next section shows the response DIG received from the query to the DNS server.  When performing PD work this section is perhaps the most important section.

  • opcode: QUERY - The response from the DNS Server.
  • status:  NOERROR - One of several status messages about this query.  The possible response codes follow.
    • 0 = NOERROR - No Errors (Desired result)
    • 1 = FORMERR - Format error - cannot understand the query
    • 2 = SERVFAIL - Name server problem
    • 3 = NXDOMAIN - Domain does not exist  (Only from authoritative server)
    • 4 = NOTIMPL - Not Implemented
    • 5 = REFUSED - e.g.  Refused zone transfer requests - Or policy reasons such as this server is not available for public use.
  • id: 50815 - The transaction number
  • flags: qr rd ra ad - This part and the status are the most important sections to review.  The meaning of each flag is shown below.
    • AA = Authoritative Answer (Answer was from an authoritative NS for that zone.)
    • TC = Truncation - Answer was truncated
    • RD = Recursion Desired - Set in the query to the name server and copied into the response if recursion is supported.
    • RA = Recursion Available - If set this denotes recursive query support is available.  In this example we queried 8.8.8.8 which is Google's public DNS server and recursion is available.  If we queried the one of the root name servers recursion is NOT available.
    • AD = Authenticated Data (DNSSEC Only) - The data was authenticated
    • CD = Checking Disabled (DNSSEC Only) - Disables checking at the receiving server.
  • The next four values are pretty self explanatory.  Especially after using DIG for a while.
    • QUERY: 1 - In this example we sent one query to the NS.
    • ANSWER: 1 - We received one answer.  It would be zero if we didn't receive an answer.  And it could be many more depending on our query and the results.
    • AUTHORITY: 0 - In this instance our answer was not from an authoritative name server.
    • ADDITIONAL: 1 - In this example the EDNS information is additional information.  If other additional information was available another section called 'ADDITIONAL SECTION' would appear in our results.

;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50815
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

The additional section in this example.  And the default behavior of the latest DIG.  EDNS is necessary for DNSSEC.  This section may be suppressed by adding the '+noedns' flag.

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512

This is obviously the question we sent to the name server.  In this instance we can note that we expect the answer to be an "A" record.  This may be suppressed with the '+noquestion' flag.

;; QUESTION SECTION:
;isc.org. IN A

This is the information we wanted.

;; ANSWER SECTION:
isc.org. 59 IN A 149.20.64.69

This section provides statistics about our query.  It may be suppressed with the '+nostats' flag.

;; Query time: 107 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sun Jun 05 06:47:57 UTC 2016
;; MSG SIZE rcvd: 52

JusT The Facts Ma'am

If you just want a quick answer to your question there is an easy way to suppress all of the extra information.  As stated above you can suppress each section.  But this adds a lot of typing and flags to your query.  The quick and dirty method is to use the '+short' flag.  And for a bit more information the '+short +noshort' flags.  See the examples below.

To just get the answer add the '+short' flag.

# dig @8.8.8.8 +short isc.org
149.20.64.69

# dig @8.8.8.8 +short -x 149.20.64.69
www.isc.org.

To get a bit more information add the '+short +noshort' flag.

# dig @8.8.8.8 +short +noshort isc.org
isc.org. 57 IN A 149.20.64.69

# dig @8.8.8.8 +short +noshort -x 149.20.64.69
69.64.20.149.in-addr.arpa. 3599 IN PTR www.isc.org.

Another way to get a short answer is to use '+noall +answer'.  The '+noall' flag will suppress everything.  And then add the '+answer' flag to just get the answer as shown with the flags '+short +noshort'.

Using .digrc

If you have certain options you would always like to use.  Or if you have a long list of queries to make and you don't want the extra sections in your results, you may use the ~/.digrc file.  Simply create this file in your home directory and add the flags you want on a single line.  To get rid of the command section, EDNS section, question section, and the stats section add the following to your .digrc file.

# cat .digrc
+nocmd +nostats +noedns +noquestion

OTHER QUERY OPTIONS

In the examples below we set the flags '+nocmd +nostats +nodns +noquestion' in our .digrc file.  This will make the results a bit clearer.  I am leaving the flags section.

Reverse Resolution

Use the '-x' flag and enter the IP address.  This will give you the PTR record for this IP address.

# dig @8.8.8.8 -x 149.20.64.69
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 24123
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; ANSWER SECTION:
69.64.20.149.in-addr.arpa. 2748 IN PTR www.isc.org.

Query Various TYPES - A,NS, SOA, MX, TXT, ANY & in-addr.arpa

You can query for specific information by simply adding the type at the end of your query.  Actually the order isn't even that important.  And case isn't important either.  The search for the A record is not shown below.  This is the default behavior if no other type is specified.

# dig @8.8.8.8 isc.org NS

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @8.8.8.8 isc.org NS
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31500
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 0

;; ANSWER SECTION:
isc.org. 7199 IN NS ams.sns-pb.isc.org.
isc.org. 7199 IN NS sfba.sns-pb.isc.org.
isc.org. 7199 IN NS ns.isc.afilias-nst.info.
isc.org. 7199 IN NS ord.sns-pb.isc.org.

# dig @8.8.8.8 isc.org SOA

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @8.8.8.8 isc.org SOA
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64161
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; ANSWER SECTION:
isc.org. 7199 IN SOA ns-int.isc.org. hostmaster.isc.org. 2016053100 7200 3600 24796800 3600

# dig @8.8.8.8 +multiline isc.org SOA

The '+multiline' flag makes reading the SOA information a bit easier.

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @8.8.8.8 +multiline isc.org SOA
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10321
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; ANSWER SECTION:
isc.org. 6545 IN SOA ns-int.isc.org. hostmaster.isc.org. (
              2016053100 ; serial
              7200 ; refresh (2 hours)
              3600 ; retry (1 hour)
              24796800 ; expire (41 weeks)
              3600 ; minimum (1 hour)
)

# dig @8.8.8.8 isc.org MX

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @8.8.8.8 isc.org MX
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41208
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; ANSWER SECTION:
isc.org. 7199 IN MX 10 mx.pao1.isc.org.
isc.org. 7199 IN MX 10 mx.ams1.isc.org.

# dig @8.8.8.8 isc.org TXT

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @8.8.8.8 isc.org TXT
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20005
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; ANSWER SECTION:
isc.org. 7199 IN TXT "v=spf1 a mx ip4:204.152.184.0/21 ip4:149.20.0.0/16 ip6:2001:04F8::0/32 ip6:2001:500:60::65/128 ~all"
isc.org. 7199 IN TXT "google-site-verification=6v652rgkk_kI6Ky32iGdxqXjQ4_BAd5DYKsrnRXKUiE"

The 'ANY' flag will search for all types.  It is not included here as it provides tons of data.  And it also provides all of the DNSSEC data which is terribly difficult to display or read.

There are other types of searches available.  Not covered in this document is how to search for various DNSSEC record types.

To search for reverse delegation we need to use the 'in-addr.arpa' for our IP addresses.

# dig @8.8.8.8 64.149.in-addr.arpa NS

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @8.8.8.8 64.149.in-addr.arpa NS
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61318
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0

;; ANSWER SECTION:
64.149.in-addr.arpa. 21599 IN NS luna.earthlink.net.
64.149.in-addr.arpa. 21599 IN NS sol.earthlink.net.

# dig @8.8.8.8 149.in-addr.arpa

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @8.8.8.8 149.in-addr.arpa
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64416
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0

;; AUTHORITY SECTION:
149.in-addr.arpa. 1432 IN SOA z.arin.net. dns-ops.arin.net. 2016031716 1800 900 691200 10800

Delegation Search Using +trace

To quickly search forward and reverse delegation use the '+trace' flag.  You can manually do this by searching each authoritative name server in order.  In the examples below the DNSSEC information has been removed as it is difficult to read and display.

# dig @k.root-servers.net isc.org +trace

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @k.root-servers.net isc.org +trace
; (2 servers found)
;; global options: +cmd
. 518400 IN NS a.root-servers.net.
. 518400 IN NS b.root-servers.net.
. 518400 IN NS c.root-servers.net.
. 518400 IN NS d.root-servers.net.
. 518400 IN NS e.root-servers.net.
. 518400 IN NS f.root-servers.net.
. 518400 IN NS g.root-servers.net.
. 518400 IN NS h.root-servers.net.
. 518400 IN NS i.root-servers.net.
. 518400 IN NS j.root-servers.net.
. 518400 IN NS k.root-servers.net.
. 518400 IN NS l.root-servers.net.
. 518400 IN NS m.root-servers.net.
;; Received 913 bytes from 193.0.14.129#53(k.root-servers.net) in 394 ms

org. 172800 IN NS c0.org.afilias-nst.info.
org. 172800 IN NS d0.org.afilias-nst.org.
org. 172800 IN NS b2.org.afilias-nst.org.
org. 172800 IN NS b0.org.afilias-nst.org.
org. 172800 IN NS a0.org.afilias-nst.info.
org. 172800 IN NS a2.org.afilias-nst.info.
;; Received 681 bytes from 199.7.91.13#53(d.root-servers.net) in 212 ms

isc.org. 86400 IN NS ams.sns-pb.isc.org.
isc.org. 86400 IN NS ns.isc.afilias-nst.info.
isc.org. 86400 IN NS ord.sns-pb.isc.org.
isc.org. 86400 IN NS sfba.sns-pb.isc.org.
;; Received 514 bytes from 199.19.54.1#53(b0.org.afilias-nst.org) in 1303 ms

isc.org. 60 IN A 149.20.64.69
isc.org. 7200 IN NS ams.sns-pb.isc.org.
isc.org. 7200 IN NS sfba.sns-pb.isc.org.
isc.org. 7200 IN NS ns.isc.afilias-nst.info.
isc.org. 7200 IN NS ord.sns-pb.isc.org.
;; Received 1619 bytes from 199.6.0.30#53(ord.sns-pb.isc.org) in 17 ms

  • We queried the K root server and it responded with a list of all of the root servers and then the D server was queried.
  • The D root server responded with a list of NS authoritative for '.org.'.
  • The 'b0.org.afilias-nst.org' NS responds with a list of NS authoritative for 'isc.org.'.
  • Finally the 'ord.sns-pb.isc.org' NS responds with a list of the NS for 'isc.org' and the A record for 'isc.org'.

# dig @a.root-servers.net -x 149.20.64.69 +trace

; <<>> DiG 9.9.5-9+deb8u6-Raspbian <<>> @a.root-servers.net -x 149.20.64.69 +trace
; (2 servers found)
;; global options: +cmd
. 518400 IN NS e.root-servers.net.
. 518400 IN NS h.root-servers.net.
. 518400 IN NS l.root-servers.net.
. 518400 IN NS i.root-servers.net.
. 518400 IN NS a.root-servers.net.
. 518400 IN NS d.root-servers.net.
. 518400 IN NS c.root-servers.net.
. 518400 IN NS b.root-servers.net.
. 518400 IN NS j.root-servers.net.
. 518400 IN NS k.root-servers.net.
. 518400 IN NS g.root-servers.net.
. 518400 IN NS m.root-servers.net.
. 518400 IN NS f.root-servers.net.
;; Received 913 bytes from 198.41.0.4#53(a.root-servers.net) in 374 ms

in-addr.arpa. 172800 IN NS e.in-addr-servers.arpa.
in-addr.arpa. 172800 IN NS f.in-addr-servers.arpa.
in-addr.arpa. 172800 IN NS d.in-addr-servers.arpa.
in-addr.arpa. 172800 IN NS c.in-addr-servers.arpa.
in-addr.arpa. 172800 IN NS b.in-addr-servers.arpa.
in-addr.arpa. 172800 IN NS a.in-addr-servers.arpa.
;; Received 738 bytes from 198.41.0.4#53(a.root-servers.net) in 263 ms

149.in-addr.arpa. 86400 IN NS r.arin.net.
149.in-addr.arpa. 86400 IN NS u.arin.net.
149.in-addr.arpa. 86400 IN NS z.arin.net.
149.in-addr.arpa. 86400 IN NS y.arin.net.
149.in-addr.arpa. 86400 IN NS x.arin.net.
149.in-addr.arpa. 86400 IN NS arin.authdns.ripe.net.
;; Received 385 bytes from 203.119.86.101#53(e.in-addr-servers.arpa) in 381 ms

20.149.in-addr.arpa. 86400 IN NS ord.sns-pb.isc.org.
20.149.in-addr.arpa. 86400 IN NS ams.sns-pb.isc.org.
20.149.in-addr.arpa. 86400 IN NS sfba.sns-pb.isc.org.
;; Received 383 bytes from 199.180.180.63#53(r.arin.net) in 143 ms

69.64.20.149.in-addr.arpa. 3600 IN PTR www.isc.org.
64.20.149.in-addr.arpa. 3600 IN NS sfba.sns-pb.isc.org.
64.20.149.in-addr.arpa. 3600 IN NS ord.sns-pb.isc.org.
64.20.149.in-addr.arpa. 3600 IN NS ams.sns-pb.isc.org.
;; Received 1639 bytes from 199.6.1.30#53(ams.sns-pb.isc.org) in 117 ms

Creating the Root Hints File

A quick one line command to create a root hints file for your DNS server.  The IP addresses for the root servers do change on rare occasions.

# dig @a.root-servers.net . NS >root.hints

NSLOOKUP

Just a few quick examples on how to query using nslookup.  I am adding the NS to use.

  • nslookup isc.org 8.8.8.8
  • nslookup 149.20.64.69 8.8.8.8
  • nslookup -query=NS isc.org 8.8.8.8
  • -query=[NS,A,ANY,MX,SOA,TXT etc etc]
  • nslookup -debug isc.org 8.8.8.8  (debugging)
  • nslookup -d2 isc.org 8.8.8.8  (more detailed debugging)

GETOPTS and OPTIND

Understanding OPTIND

Figuring out OPTIND in shell scripting can be difficult.  And if you don't touch a script for a while it is an easy thing to forget.  This is a quick post to help explain OPTIND while using GETOPTS.

Definitions and Explanations

OPTIND Definition = The index of the next argument to be processed by GETOPTS.  By default the system initializes this value to 1.

GETOPTS Flags

  • a: = If a flag is followed by a colon (e.g. 'a:') an argument is required. This is OPTARG.
  • a = A flag with no colon does not require an additional argument.

 Quick Script to Help Explain

The script below will be used to help explain OPTIND and other GETOPTS settings.

#!/bin/bash
#
# Quick and dirty script to explain getopts
# OPTIND SHIFT and $#
#

echo BEFORE GETOPTS OPTIND = "$OPTIND"
while getopts "xzyc:b:e:hv" flag
do
echo FLAG="$flag" OPTIND="$OPTIND" OPTARG="$OPTARG"
done
echo
echo ALL PASSED PARMS \(\$@\) = "$@"
echo Total Num of PARMS \(\$#\) = "$#"
echo SHIFT of OPTIND minus 1 aka
echo OPTIND = "$OPTIND" minus SHIFTING NUM = `expr $OPTIND - 1`
echo Before SHIFT ARG1 \(\$1\) = $1
shift `expr $OPTIND - 1`
echo AFTER SHIFT ARG1 \(\$1\) = $1

#EOF

Examples

Using "xyzc:b:e:hv" as the GETOPTS flags here is how to count the arguments and OPTIND index numbers.

Here are two examples that pass the same options to GETOPTS.  But the OPTIND will be different.

  • OPTION 1:  # ./parse.sh -x -y -z -c c_arg -b b_arg ARG1 ARG2
  • OPTION 2:  # ./parse.sh -xyz -c c_arg -b b_arg ARG1 ARG2

OPTION 1 Explanation

OPTIND starts at 1 for both options.

  • GETOPTS will parse the flag '-x' and the OPTIND index will increase to 2
  • Parse the '-y' flag and the OPTIND index will increase to 3
  • Parse the '-z' flag and the OPTIND index will increase to 4
  • Parse the '-c c_arg' flag and the OPTIND index will increase to 6.  The '-c' will increase the OPTIND.  And the 'c_arg' will be set as OPTARG and also increase the OPTIND index number.
  • Parse the '-b b_arg' flag and the OPTIND index will increase to 8.

The final OPTIND index number is 8.  The total number of parameters ($#) parsed by GETOPTS is 9 after counting both ARG1 and ARG2.

OPTION 2 Explanation

Again OPTIND starts at 1.

  • GETOPTS will parse the flag '-xyz'.  But instead of increasing the index for X and Y the OPTIND index will only increase to 2 after GETOPTS parses 'z'.  Three flags are combined into one flag as none of them require a separate argument (OPTARG).
  • Parse the '-c c_arg' flag and increase OPTIND by 2 just like in OPTION 1.  So OPTIND will change from 2 to 4 after parsing this flag.
  • Parse the '-b b_arg' flag and the and the OPTIND index will increase to 6.

The final OPTIND index number is 6.  The total number of parameters ($#) parsed by GETOPTS is 7 after counting both ARG1 and ARG2.  The '-xyz' flag only counts as one parameter and only increases OPTIND by 1.

Script Output

To make this clearer here is the output of the script after running each option.

OPTION 1:

# ./parse.sh -x -y -z -c c_arg -b b_arg ARG1 ARG2
BEFORE GETOPTS OPTIND = 1
FLAG=x OPTIND=2 OPTARG=
FLAG=y OPTIND=3 OPTARG=
FLAG=z OPTIND=4 OPTARG=
FLAG=c OPTIND=6 OPTARG=c_arg
FLAG=b OPTIND=8 OPTARG=b_arg

ALL PASSED PARMS ($@) = -x -y -z -c c_arg -b b_arg ARG1 ARG2
Total Num of PARMS ($#) = 9
SHIFT of OPTIND minus 1 aka
OPTIND = 8 minus SHIFTING NUM = 7
Before SHIFT ARG1 ($1) = -x
AFTER SHIFT ARG1 ($1) = ARG1


OPTION 2:

# ./parse.sh -xyz -c c_arg -b b_arg ARG1 ARG2
BEFORE GETOPTS OPTIND = 1
FLAG=x OPTIND=1 OPTARG=
FLAG=y OPTIND=1 OPTARG=
FLAG=z OPTIND=2 OPTARG=
FLAG=c OPTIND=4 OPTARG=c_arg
FLAG=b OPTIND=6 OPTARG=b_arg

ALL PASSED PARMS ($@) = -xyz -c c_arg -b b_arg ARG1 ARG2
Total Num of PARMS ($#) = 7
SHIFT of OPTIND minus 1 aka
OPTIND = 6 minus SHIFTING NUM = 5
Before SHIFT ARG1 ($1) = -xyz
AFTER SHIFT ARG1 ($1) = ARG1