├── open-ports.service
├── open-ports.timer
├── README.md
├── open_ports_install_linux.sh
├── open_ports_install_os_x.sh
├── LICENSE
└── open_ports.sh
/open-ports.service:
--------------------------------------------------------------------------------
1 | [Service]
2 | Type=oneshot
3 | ExecStart=/usr/bin/open_ports.sh
4 |
--------------------------------------------------------------------------------
/open-ports.timer:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=Update open-ports' database
3 |
4 | [Timer]
5 | OnCalendar=*-*-* *:0/2
6 |
7 | [Install]
8 | WantedBy=timers.target
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | open-ports
2 | ==========
3 |
4 | A bash-script for OS X and Linux detailing the open network connections to and from a computer
5 |
6 | 
7 |
8 | More information about the script can be found here:
9 | http://cs.lth.se/peter-moller/script/open-portssh-en/
10 |
11 | -----
12 |
13 | Birds eye view of how the script works:
14 | ---------------------------------------
15 | * When run as root, data is generated and stored on disk
16 | * When run as any other user, data is presented from those files
17 | * Optionally, GeoLookup is done from http://api.db-ip.com (requires a free key)
18 | Result from that is stored on disk to speed up future lookups
19 | * The external address is checked with http://ipecho.net
20 | * IP address (as well as default interface, checked against `www.lu.se`)
21 |
22 | *One clarification: the script **needs** to run as root, or you will only see your own connections and that makes it much less valuable!*
23 |
24 | Other features:
25 | ---------------
26 | * The external IP-address is checked every hour to see if it has been changed
27 | * The age of the data files are checked: if they are older than 1 hour, a warnng is printed
28 | * Once every week the script looks for a new version of itself and notifies the user accordingly
29 | * Every two hours the checksum of the “lsof” binary is checked to look for intrusions: if it has been changed a warning is printed instead of output
30 | * On OS X only:
31 | * lists all interfaces, in priority order
32 | * looks for available software updates every 6 hours
33 | * When the script has been installed, or updated, a “signal” is send to me (a curl to a specific URL that I check for in the apache-log on the dept. server. This is done out of curiosity of how many installs and updates there are, and no information is used in any other way)
34 |
35 | Tha basic functionality of the script can be encapsulated in:
36 | ESTABLISHED connections (Darwin, `IPv4`; replace the `4` with a `6` for `IPv6`):
37 | `lsof +c 0 -i 4 -n | grep EST | sort -f -k 1,1 | cut -d\( -f1 | awk '{ print $1" "$3" "$9 }' | sed -e 's/\ [[:digit:]].*-\>/\ /g' -e 's/:/\ /g' | sort -f | uniq -c`
38 | and
39 | LISTEN connections (Darwin, same as above, almost...):
40 | `lsof +c 0 -i 4 -n | grep LISTEN | sort -f -k 1,1 | cut -d\( -f1 | awk '{ print "4 - "$1" "$3" "$9 }' | sed -e 's/:/\ /g' -e 's/\ [[:digit:]]\{2,5\}$/\ anonymous_port/g' | uniq`
41 | For Linux the central lines are almost the same.
42 |
43 |
44 | Operation of the script, in line-order:
45 | ----------------------------------------------------
46 | 1. Quit if either:
47 | - `open_ports.sh` is already running with the same `$UID`
48 | - the OS is not Darwin or Linux
49 | 2. Functions
50 | 3. Definitions of variables (I'm unsure if they “should” come before the functions, but I'm pretty sure it doesn't matter… :-)
51 | 4. If script is run by `root`, generate data and then exit
52 | 5. Checks:
53 | - is there an update?
54 | - is there a STOP-flag (`lsof` has been changed)? If so, notify user and exit the script
55 | - Is there any data file at all? Warn and exit if not
56 | - If OS X: check to see if the `launchd`-part is running. Warn if not
57 | - Are the data files older than 1 hour? Warn if so
58 | - Do we have an IP address (rather: do we have a default interface – checked against `www.lu.se`)? Warn otherwise
59 | 6. Find out, and print system information
60 | 7. If OS X: look for software updates (this is done every 6 houres; result stored in `/tmp/swu.temp`)
61 | 8. Print the head
62 | 9. Print the ESTABLISHED files (IPv4 first, IPv6 next)
63 | 10. Print the LISTEN files
64 |
65 |
66 | When the script has been modified, I (manually) move it to the deployment-server, OpenPortsURL
67 | (http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts), and create a `sha1`-file so that clients may
68 | get information about a new version being released.
69 |
--------------------------------------------------------------------------------
/open_ports_install_linux.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Script to install open_ports.sh on Linux
3 | # © Peter Möller, 2011-2012
4 | # open_ports.sh home page (english):
5 | # http://cs.lth.se/kontakt/peter_moller/script/open_portssh_en
6 | # open_ports.sh home page (swedish):
7 | # http://cs.lth.se/kontakt/peter_moller/script/open_portssh
8 | #
9 | # 2011-03-10 / Peter Möller, Datavetenskap, LTH
10 | # 2011-11-17: Fixed a bug that wiped out a previous crontab
11 | # 2011-11-30: Small fix
12 | # 2015-09-16: Moved to GitHub
13 | # Location:
14 | # http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts/open_ports_install_linux.sh
15 |
16 |
17 | # Find out what OS is running. Quit if not Mac OS X or Linux
18 | OS="$(uname -s)"
19 | if [ ! "$OS" = "Darwin" -a ! "$OS" = "Linux" ]; then
20 | echo "Unknown Operating System!!! (according to \"uname -s\")"
21 | echo "This script only works on Mac OS X or Linux."
22 | echo "Exiting..."
23 | exit 1
24 | fi
25 |
26 | # Make sure the user is "root"
27 | if [ ! "$USER" = "root" ] ; then
28 | echo "Must be run by root!"
29 | echo "Exiting..."
30 | exit 1
31 | fi
32 |
33 | # Inform the user of what is going to happen
34 | printf "\e[1;4mInstallation of open_ports.sh:\e[0m\n"
35 | echo "This will install \"open_ports.sh\" on your computer."
36 | echo
37 | echo "The home page for the project is located here:"
38 | echo "http://cs.lth.se/kontakt/peter_moller/script/open_portssh_en"
39 | echo "There you will find more information about the script and also how to remove it."
40 | echo
41 | echo "Now the script will be downloaded and installed:"
42 |
43 | # Check to see if "curl" exists
44 | if [ -z "$(which -a curl 2>/dev/null)" ]; then
45 | echo "Warning: \"curl\" not found! Update of script will not work!"
46 | fi
47 |
48 | # make sure openssl exists
49 | if [ -z $(which openssl) ]; then
50 | echo "Warning: \"openssl\" not found! Checksum-verification will not work!"
51 | fi
52 |
53 | # BINDIR points to the "binary"
54 | BINDIR="/usr/bin"
55 | # PREFIX points to where all the datafiles are stored
56 | PREFIX="/usr/share/cs.lth.se/OpenPorts"
57 | # IP_CACHE is a growing list of IP-addresses and their geo location.
58 | # Since this is being used by other scripts, it's not in the OpenPorts directory
59 | IP_CACHE="/usr/share/cs.lth.se/ip_cache.txt"
60 | # GeoLookupDir is a dir where the geo lookup is stored
61 | GeoLookupDir="/usr/share/cs.lth.se/GeoLookup"
62 | # EXTERN stores the computers "external" address. Checked hourly
63 | EXTERN="$PREFIX/ExternIP.txt"
64 | # FILE4 stores current IPv4-ESTABLISHED connections. Generated every two minutes!
65 | FILE4="$PREFIX/ip4.txt"
66 | # FILE6 stores current IPv6-ESTABLISHED connections. Generated every two minutes!
67 | FILE6="$PREFIX/ip6.txt"
68 | # FILE_LISTEN stores current LISTEN connections. Generated every two minutes!
69 | FILE_LISTEN="$PREFIX/listen.txt"
70 | # CHECKSUM stores a sha1-checksum for the lsof-binary. Cheched every two houres
71 | CHECKSUM="$PREFIX/Checksum.txt"
72 | # IP_LOCATE_CACHE is a temporary file that stores the geo location of the computers external address
73 | IP_LOCATE_CACHE="$PREFIX"/ip_locate_cache.txt
74 | # OP_LOGG is a log file where all things related to open_ports.sh (install and upgrades) are noted
75 | OP_LOGG="$PREFIX"/OpenPorts_log.txt
76 |
77 |
78 |
79 | # fetch the open_ports-script
80 | printf "1. Fetching the main script (installs in \"$BINDIR\")..."
81 | #curl -o $BINDIR/open_ports.sh http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts/open_ports.sh 2>/dev/null
82 | curl -o /tmp/open_ports.sh http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts/open_ports.sh 2>/dev/null
83 | curl -o /tmp/open_ports.sh.sha1 http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts/open_ports.sh.sha1 2>/dev/null
84 | if [ "$(openssl sha1 /tmp/${ScriptName} | awk '{ print $2 }')" = "$(less /tmp/${ScriptName}.sha1)" ]; then
85 | mv /tmp/open_ports.sh /usr/bin/open_ports.sh
86 | chmod 755 $BINDIR/open_ports.sh
87 | else
88 | echo "Checksum does NOT match!! Installation aborted!"
89 | exit 1
90 | fi
91 |
92 | # Countries.txt
93 | curl -o /tmp/Countries.txt http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts/Countries.txt 2>/dev/null
94 | curl -o /tmp/Countries.txt.sha1 http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts/Countries.txt.sha1 2>/dev/null
95 | if [ "$(openssl sha1 /tmp/Countries.txt | awk '{ print $2 }')" = "$(less /tmp/Countries.txt.sha1)" ]; then
96 | mv /tmp/Countries.txt ${PREFIX}/Countries.txt
97 | rm /tmp/Countries.txt.sha1 2>/dev/null
98 | fi
99 | printf " done!\n"
100 |
101 | # Fix cron
102 | command -v systemctl >/dev/null 2>&1
103 | if [ $? -eq 0 ]; then
104 | printf "2. Adding systemd unit to run the script every two minutes.\n"
105 | cp /home/pmoreau/softwares/open-ports/open-ports.timer /etc/systemd/system/
106 | cp /home/pmoreau/softwares/open-ports/open-ports.service /etc/systemd/system/
107 | systemctl enable open-ports.timer
108 | systemctl start open-ports.timer
109 | else
110 | command -v crontab >/dev/null 2>&1
111 | if [ $? -eq 0]; then
112 | printf "2. Fixing crontab for root (crontab runs the script every two minutes.\n"
113 | printf " This will NOT mess up previous crontab entries)..."
114 | crontab -l | grep -v "open_ports.sh" > /tmp/CRONFILE
115 | echo "*/2 * * * * $BINDIR/open_ports.sh" >> /tmp/CRONFILE
116 | crontab < /tmp/CRONFILE
117 | rm /tmp/CRONFILE
118 | printf " done!\n"
119 | else
120 | echo "systemd nor cron found on your computer: open-ports data won't be updated automatically"
121 | fi
122 | fi
123 |
124 |
125 | # Create the directory for the files and set the access rights
126 | printf "3. Creating the data-directories (located in \"$PREFIX\")..."
127 | mkdir -p "$PREFIX"
128 | chmod 755 "$PREFIX"
129 | mkdir "$GeoLookupDir"
130 | chmod 777 "$GeoLookupDir"
131 | #touch "$FILE4" "$FILE6" "$IP_CACHE" "$IP_LOCATE_CACHE"
132 | #chmod 666 "$FILE4" "$FILE6" "$IP_CACHE" "$IP_LOCATE_CACHE"
133 | touch "$FILE4" "$FILE6"
134 | chmod 666 "$FILE4" "$FILE6"
135 | printf " done!\n"
136 |
137 | echo
138 | printf "\e[1;4mDone!\e[0m\n"
139 | echo "\"open_ports.sh\" is now running and collect information every two minutes."
140 | echo "Run the script as an ordinary user to see the data."
141 | echo
142 | echo "In order for the geographical lookup to work, you need to get a [free] key from \"http://db-ip.com/api/\"."
143 | echo "Once you've gotten that key in your email, you need to store it as \"apidb.key\" in \"$PREFIX\""
144 | echo "Opening this address in a few seconds..."
145 | /bin/sleep 5
146 | xdg-open "http://db-ip.com/api/free" &
147 | echo
148 | echo "Please do not forget to upgrade the script once every month or so! (\"open_ports.sh -u\")"
149 | echo "Also, please feel free to report bugs and email suggestions for improvements!"
150 | echo "Thank you!"
151 | echo "Peter Möller, Department of Computer Science, Lund University, Lund, Sweden"
152 |
153 | # Make an entry into the log book
154 | echo "$(date): \"open_ports.sh\" installed" >> "$OP_LOGG"
155 |
156 | exit 0
157 |
--------------------------------------------------------------------------------
/open_ports_install_os_x.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Script to install open_ports.sh
3 | # © Peter Möller, 2011-2012
4 | # 2011-05-05 / Peter Möller, Datavetenskap, LTH
5 | # 2011-11-17: Fixed check of OS X version to determine which GeekTool to use
6 | # 2011-12-06: Added printout during installation
7 | # 2014-03-02: Changed to accomodated
8 | # 2015-09-16: Moved to GitHub
9 | # Location:
10 | # http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts/open_ports_install.sh
11 |
12 |
13 | # Make sure the user is "root"
14 | if [ ! "$USER" = "root" ] ; then
15 | echo "Must be run by root!"
16 | echo "Exiting..."
17 | exit 1
18 | fi
19 |
20 | # ScriptName is the name of the script
21 | ScriptName="open_ports.sh"
22 |
23 | # Determine what OS is running and warn if not 10.6 or 10.7:
24 | SW_VERS="$(sw_vers -productVersion | cut -d\. -f2)"
25 | if [ -z "$(echo "6789" | grep -o $SW_VERS)" ]; then
26 | echo "\"$ScriptName\" has not been tried with Mac OS X 10.$SW_VERS!!"
27 | echo "It may not work."
28 | fi
29 |
30 |
31 | # BINDIR points to the "binary"
32 | BINDIR="/usr/local/bin"
33 | # PREFIX points to where all the datafiles are stored
34 | PREFIX="/Library/cs.lth.se/OpenPorts"
35 | ## IP_CACHE is a growing list of IP-addresses and their geo location.
36 | ## Since this is being used by other scripts, it's not in the OpenPorts directory
37 | #IP_CACHE="/Library/cs.lth.se/ip_cache.txt"
38 | # GeoLookupDir is a dir where the geo lookup is stored
39 | GeoLookupDir="/Library/cs.lth.se/GeoLookup"
40 | # EXTERN stores the computers "external" address. Checked hourly
41 | EXTERN="$PREFIX/ExternIP.txt"
42 | # FILE4 stores current IPv4-ESTABLISHED connections. Generated every two minutes!
43 | FILE4="$PREFIX/ip4.txt"
44 | # FILE6 stores current IPv6-ESTABLISHED connections. Generated every two minutes!
45 | FILE6="$PREFIX/ip6.txt"
46 | # FILE_LISTEN stores current LISTEN connections. Generated every two minutes!
47 | FILE_LISTEN="$PREFIX/listen.txt"
48 | # CHECKSUM stores a sha1-checksum for the lsof-binary. Cheched every two houres
49 | CHECKSUM="$PREFIX/Checksum.txt"
50 | ## IP_LOCATE_CACHE is a temporary file that stores the geo location of the computers external address
51 | #IP_LOCATE_CACHE="$PREFIX"/ip_locate_cache.txt
52 | # OP_LOGG is a log file where all things related to open_ports.sh (install and upgrades) are noted
53 | OP_LOGG="$PREFIX"/OpenPorts_log.txt
54 |
55 | # Inform the user of what is going to happen
56 | printf "\e[1;4mInstallation of \"$ScriptName\":\e[0m\n"
57 | echo "This will install \"$ScriptName\" on your computer."
58 | echo
59 | echo "The home page for the project is located here:"
60 | echo "http://cs.lth.se/kontakt/peter_moller/script/open_portssh_en"
61 | echo "There you will find more information about the script and also how to remove it."
62 | echo
63 | echo "Now the script will be downloaded and installed:"
64 |
65 | # Fetch and launch the launchd-component
66 | printf "1. Fetching the launchd-component (runs the script every two minutes)..."
67 | curl -o /Library/LaunchDaemons/se.lth.cs.open_ports.plist http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts/se.lth.cs.open_ports.plist 2>/dev/null
68 | chmod 644 /Library/LaunchDaemons/se.lth.cs.open_ports.plist
69 | launchctl load /Library/LaunchDaemons/se.lth.cs.open_ports.plist
70 | launchctl start se.lth.cs.open_ports
71 | printf " done!\n"
72 |
73 | # Fetch the script
74 | printf "2. Fetching the main script and the country list..."
75 | # open_ports.sh
76 | curl -o /tmp/${ScriptName} http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts/${ScriptName} 2>/dev/null
77 | curl -o /tmp/${ScriptName}.sha1 http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts/${ScriptName}.sha1 2>/dev/null
78 | if [ "$(openssl sha1 /tmp/${ScriptName} | awk '{ print $2 }')" = "$(less /tmp/${ScriptName}.sha1)" ]; then
79 | mkdir -p /usr/local/bin 2>/dev/null
80 | mv /tmp/${ScriptName} ${BINDIR}/${ScriptName}
81 | chmod 755 ${BINDIR}/${ScriptName}
82 | else
83 | echo "Checksum does NOT match!! Installation aborted!"
84 | exit 1
85 | fi
86 | # Countries.txt
87 | curl -o /tmp/Countries.txt http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts/Countries.txt 2>/dev/null
88 | curl -o /tmp/Countries.txt.sha1 http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts/Countries.txt.sha1 2>/dev/null
89 | if [ "$(openssl sha1 /tmp/Countries.txt | awk '{ print $2 }')" = "$(less /tmp/Countries.txt.sha1)" ]; then
90 | mv /tmp/Countries.txt ${PREFIX}/Countries.txt
91 | rm /tmp/Countries.txt.sha1 2>/dev/null
92 | fi
93 | printf " done!\n"
94 |
95 | # Create the directory for the files and set the access rights
96 | printf "3. Creating the data-directories..."
97 | mkdir -p "$PREFIX"
98 | chmod 755 "$PREFIX"
99 | mkdir "$GeoLookupDir"
100 | chmod 777 "$GeoLookupDir"
101 | touch "$FILE4" "$FILE6"
102 | chmod 666 "$FILE4" "$FILE6"
103 | printf " done!\n"
104 |
105 | # Send a signal that someone has installed the script
106 | # This is only to give me feedback that someone is actually using this
107 | # I will *not* use the data in any way or give it away!
108 | curl -s -f -e "$ScriptName OS X 10.${SW_VERS}" -o /dev/null http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts/installed 2>/dev/null
109 |
110 | echo "Done installing base parts of \"$ScriptName\". Now proceeding to install GeekTool"
111 | echo "(GeekTool is not a part of \"$ScriptName\"; it is used to display the output of the script"
112 | echo "on the desktop of your computer. You may skip it if you like)."
113 | echo
114 |
115 | # Getting GeekTool
116 | if [ -z "$(ls /Library/PreferencePanes/GeekTool.prefPane 2>/dev/null)" -a -z "$(ls /Users/*/Library/PreferencePanes/GeekTool.prefPane 2>/dev/null)" -a -z "$(ls /Applications/GeekTool.app 2>/dev/null)" ]; then
117 | if [ "$SW_VERS" = "6" ]; then
118 | echo "Fetching GeekTool for Snow Leopard"
119 | # Get GeekTook
120 | curl -o /tmp/GeekTool.dmg http://update.tynsoe.org/geektool3/Public/GeekTool%203.0.dmg 2>/dev/null
121 | hdiutil mount /tmp/GeekTool.dmg
122 | open /Volumes/GeekTool\ 3/
123 | echo "GeekTool has been downloaded, but you must install it yourself!"
124 | elif [ "$SW_VERS" = "7" -o "$SW_VERS" = "8" -o "$SW_VERS" = "9" -o "$SW_VERS" = "10" -o "$SW_VERS" = "11" ]; then
125 | echo "GeekTool is available from this address:"
126 | echo "http://projects.tynsoe.org/en/geektool/download.php"
127 | echo "Opening this address in a few seconds..."
128 | /bin/sleep 5
129 | open "http://projects.tynsoe.org/en/geektool/download.php" &
130 | else
131 | echo "Sorry: you are running a version of Mac OS X that will not work with GeekTool."
132 | echo "You will have to find a version for yourself..."
133 | fi
134 | else
135 | echo "It looks as if you already have GeekTool installed."
136 | fi
137 |
138 | echo
139 | printf "\e[1;4mDone!\e[0m\n"
140 | echo "\"$ScriptName\" is now running and collect information every two minutes."
141 | echo "Run the script as an ordinary user to see the data."
142 | echo
143 | printf "\e[1;3mLocations:\e[0m\n"
144 | echo "The script is located in \"${BINDIR}\""
145 | echo "The data files are stored in \"$PREFIX\""
146 | echo "The launchd-file is \"/Library/LaunchDaemons/se.lth.cs.open_ports.plist\""
147 | echo "These are the files you need to remove to uninstall!"
148 | echo
149 | echo "In order for the geographical lookup to work, you need to get a [free] key from \"http://db-ip.com/api/\"."
150 | echo "Once you've gotten that key in your email, you need to store it as \"apidb.key\" in \"$PREFIX\""
151 | echo "Opening this address in a few seconds..."
152 | /bin/sleep 5
153 | open "http://db-ip.com/api/free" &
154 | echo
155 | echo "Please do not forget to upgrade the script once every month or so! (\"$ScriptName -u\")"
156 | echo "(I would suggest that you do this from \"root\"_s crontab)"
157 | echo
158 | echo "Also, please feel free to report bugs and email suggestions for improvements!"
159 | echo "Thank you!"
160 | echo "Peter Möller, Department of Computer Science, Lund University, Lund, Sweden"
161 |
162 | # Make an entry into the log book
163 | echo "$(date): \"open_ports.sh\" installed" >> "$OP_LOGG"
164 | exit 0
165 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/open_ports.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Script to list open TCP-connections on Mac OS X 10.6, 10.7, 10.8, 10.9, 10.10 and 10.11 and Linux
4 | # The script came to life in 2011
5 | #
6 | # Copyright 2015 Peter Möller, Dept of Copmuter Science, Lund University
7 | #
8 | # Licensed under the Apache License, Version 2.0 (the "License");
9 | # you may not use this file except in compliance with the License.
10 | # You may obtain a copy of the License at
11 | #
12 | # http://www.apache.org/licenses/LICENSE-2.0
13 | #
14 | # Unless required by applicable law or agreed to in writing, software
15 | # distributed under the License is distributed on an "AS IS" BASIS,
16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | # See the License for the specific language governing permissions and
18 | # limitations under the License.
19 | #
20 | #
21 | # Script home page (english):
22 | # http://cs.lth.se/kontakt/peter_moller/script/open_portssh_en
23 | # Script home page (swedish):
24 | # http://cs.lth.se/kontakt/peter_moller/script/open_portssh
25 | # 2011-06-23 All comments translated to english (phew!)
26 | # 2011-07-13 Auto-update disabled! Instead, it notify the user of updates
27 | # Also feedback for when data is generated
28 | # Bug-fix from Roman Weber about IPv6-parsing (thanks!)
29 | # 2011-08-27 Changed URL of "whatismyip"
30 | # 2011-11-30 Polished
31 | # 2011-12-07 Version included in curl call
32 | # 2013-03-11 Disabled the use of geoiptool (sadly). Looking for a replacement
33 | # Also changed the external IP-address lookup
34 | # 2013-04-23 Fixed garbage in the $IP_CACHE-file
35 | # 2014-03-01 Implemented a new IP-lookup system using http://db-ip.com/ (Thank you, guys!)
36 | # 2015-09-16 Moved to GitHub (finally!)
37 | # 2021-01-26 Removed the update functionality. Everything now goes via git
38 | #
39 | # Version:
40 | VER="3.5"
41 | #
42 | # Note: The script is dependant on two external web-addresses:
43 | # 1. http://api.db-ip.com/addrinfo?addr=8.9.10.11&api_key=123456789123456789
44 | # Performs the mapping from IP address to Country and City
45 | # One must register by them and get a key (stored in $PREFIX/apidb.key)
46 | # Also, one must not perform more than 5.000 lookups per day
47 | # 2. http://tejji.com/ip/my-ip-address.aspx
48 | # Finds out the external IP-address you have if you are behind a NAT-router
49 | #
50 | # Adaption to Linux (Mandriva)
51 | # Lines that start with "##" are “issues” from Mac OS X to Linux
52 | #
53 | # Things to fix:
54 | # • How to present it on the screen on Linux
55 | # • IPv6/ESTABLISHED!
56 |
57 | help() {
58 | echo
59 | echo "Usage: $0 [-u]"
60 | echo
61 | echo "-u: Update the script"
62 | echo
63 | echo "If run by root: datafiles in /Library/cs.lth.se/OpenPorts (Mac) or /usr/share/cs.lth.se/OpenPorts (Linux) are created, but no output."
64 | echo "If run by any other user: output is displayed based on those datafiles."
65 | echo
66 | if [ "$OS" = "Darwin" ]; then
67 | echo "This script is supposed to be used in conjunction with a launchd-component, se.lth.cs.open_ports,"
68 | echo "that creates the datafiles in /Library/OpenPorts every two minutes. The use of GeekTool to display the result"
69 | echo "is also part of the idea behind this script!"
70 | elif [ "$OS" = "Linux" ]; then
71 | echo "This script is supposed to be used in conjunction with a cron job or a systemd timer that creates the"
72 | echo "datafiles in /usr/share/cs.lth.se/OpenPorts every two minutes. Conky can be used to display the result"
73 | echo "of this script!"
74 | fi
75 | exit 0
76 | }
77 |
78 | # Locate an IP-address. Gives:
79 | # Country: Country
80 | # City: City
81 | # to std. out
82 | # 2014-03-01: OBSOLETE!! Only here for reference
83 | locate_ip() {
84 | curl http://www.geoiptool.com/en/?IP=$1 2>/dev/null | awk '
85 | /
(Country:|City)/ {
86 | record="t";gsub("[\t ]*<[^>]*>",""); printf("%-1s ",$0);next;
87 | }
88 | record == "t" { gsub("[\t ]*<[^>]*>[\t ]*","");print $0;record="f";next}
89 | {next}
90 | END{print ""}'
91 | }
92 |
93 |
94 | # Do the Geo Lookup (if key exists)
95 | # Assumes:
96 | # - $1: IP
97 | # curl 'http://api.db-ip.com/addrinfo?addr=68.169.130.16&api_key=123456789123456789'
98 | # Gives:
99 | # - a file, $GeoLookupDir/$IP_to_check, containing "Country Name:City Name"
100 | function PerformGeoLookup ()
101 | {
102 | if [ -n "$GeoLookupKey" ]; then
103 | IP_to_check="$1"
104 | if [ -z "$(echo $IP_to_check | sed 's/[0-9\.]//g')" ]; then
105 | Rad="$(curl -s "$GeoLookupURL$IP_to_check&api_key=$GeoLookupKey")"
106 | [ "$debug" = "t" ] && echo "$(date +%F" "%T); #99; $$; User=\"$USER\"; PerformGeoLookup, IP_to_check=\"$IP_to_check\", Rad=\"$Rad\"" >> $IP_loggfile
107 | # -> Rad='{"address":"78.69.30.61","country":"SE","stateprov":"Stockholm County","city":"Farsta"}'
108 | # Simple sanity check: count the number of qoutation marks (should be 16)
109 | if [ "$(echo $Rad | grep -o '"' | wc -w | awk '{print $1}')" -eq 16 ]; then
110 | City="$(echo $Rad | cut -d\" -f 16)"
111 | Country="$(grep "$(echo $Rad | cut -d\" -f 8)" $CountryList | cut -d: -f2)"
112 | else
113 | City="???"
114 | Country="???"
115 | fi
116 | # Write to file
117 | echo "$City:$Country" > "$GeoLookupDir/${IP_to_check}.txt"
118 | [ "$debug" = "t" ] && echo "$(date +%F" "%T); #95; $$; User=\"$USER\"; PerformGeoLookup (IP=\"$IP\", IP_to_check=\"$IP_to_check\", City=\"$City\", Country=\"$Country\")" >> $IP_loggfile
119 | else
120 | City="???"
121 | Country="???"
122 | fi
123 | fi
124 | }
125 |
126 |
127 | # Check to see if $IP already exist in $GeoLookupDir and get $Country and $City
128 | # Otherwise, find the information and update $IP_CACHE
129 | # Assume:
130 | # - IP
131 | # Gives: $Country & $City and eventually a new entry in $GeoLookupDir
132 | function GetCityCountry()
133 | {
134 | # (DIRT REMOVED) DIRTY fix for IPv6. Will need to work on this!!
135 | #if [ -n "$(echo $IP | sed 's/[0-9.]//g')" ]; then
136 | # IP="$(echo $IP | cut -d: -f1)"
137 | #fi
138 | if [ -r "$GeoLookupDir/${IP}.txt" ]; then
139 | #City="$(less "$GeoLookupDir/${IP}.txt" | cut -d: -f1 | native2ascii -encoding UTF-8 -reverse)"
140 | City="$(less "$GeoLookupDir/${IP}.txt" | cut -d: -f1)"
141 | Country="$(less "$GeoLookupDir/${IP}.txt" | cut -d: -f2)"
142 | # FUTURE FEATURE: INCREASE COUNTER
143 | [ "$debug" = "t" ] && echo "$(date +%F" "%T); #135; $$; User=\"$USER\"; GetCityCountry ($IP, City=\"$City\", Country=\"$Country\")" >> $IP_loggfile
144 | else
145 | PerformGeoLookup $IP
146 | fi
147 | }
148 |
149 | # Clean the GeoLocate-cache and remove entries older than 4 weeks
150 | function CleanGeoLocate()
151 | {
152 | find "$GeoLookupDir" -type f -mtime +4w -exec rm -f {} \; 2>/dev/null
153 | }
154 |
155 |
156 | # Get DNS for $IP
157 | # Gives: $HOSTNAME
158 | # Will also deal with the private addresses:
159 | # • 10.x.x.x
160 | # • 172.16.x.x
161 | # • 192.168.x.x
162 | # as well as self-assigned address:
163 | # 169.254.x.x
164 | function GetDNS()
165 | {
166 | PrivateAddress="No"
167 | if [ -z "${IP/127.0.0.1}" ]; then
168 | HOSTNAME="localhost"
169 | elif [ "$(echo "$IP" | cut -d\. -f1)" = "10" ]; then
170 | HOSTNAME="Private address ($IP)"
171 | PrivateAddress="Yes"
172 | elif [ "$(echo "$IP" | cut -d\. -f1,2)" = "172.16" ]; then
173 | HOSTNAME="Private address ($IP)"
174 | PrivateAddress="Yes"
175 | elif [ "$(echo "$IP" | cut -d\. -f1,2)" = "192.168" ]; then
176 | HOSTNAME="Private address ($IP)"
177 | PrivateAddress="Yes"
178 | elif [ "$(echo "$IP" | cut -d\. -f1,2)" = "169.254" ]; then
179 | HOSTNAME="Self-assigned address ($IP)"
180 | PrivateAddress="Yes"
181 | else
182 | HOSTNAME_tmp="$(host -W 2 $IP)"
183 | ERR="$?"
184 | if [ ! "$ERR" = "0" ]; then
185 | HOSTNAME="$IP (DNS timeout)"
186 | # HOSTNAME="$IP could not be looked up! (DNS timeout)"
187 | else
188 | HOSTNAME=`echo $HOSTNAME_tmp | awk '{ print $NF }' | sed 's/\.$//g'`
189 | fi
190 | fi
191 | }
192 |
193 |
194 | # Quit if there already is a running “open_ports.sh”
195 | # Typical line:
196 | # 501 7307 7301 0 9:53am ttys001 0:00.02 /bin/bash /usr/bin/open_ports.sh
197 | if [ "$(ps -ef | grep "^\ *${UID}\ .*/[b]ash\ .*/[o]pen_ports.sh$" | wc -l)" -gt "2" ]; then
198 | echo "\"open_ports.sh\" already running -- will exit now"
199 | exit 0
200 | fi
201 |
202 | # Find the OS. Quit if it's not either Mac OS X or Linux
203 | OS="$(uname -s)"
204 | if [ ! "$OS" = "Darwin" -a ! "$OS" = "Linux" ]; then
205 | echo "Unknown Operating System!!!"
206 | echo "This script only works on Mac OS X or Linux."
207 | echo "Exiting..."
208 | exit 1
209 | fi
210 |
211 | # If it is Linux, figure out whether to use systemd or crontab
212 | TIMER_METHOD="none"
213 | if [ "$OS" = "Darwin" ]; then
214 | TIMER_METHOD="launchd"
215 | elif [ "$OS" = "Linux" ]; then
216 | command -v systemctl >/dev/null 2>&1
217 | if [ $? -eq 0 ]; then
218 | TIMER_METHOD="systemd"
219 | else
220 | command -v crontab >/dev/null 2>&1
221 | if [ $? -eq 0 ]; then
222 | TIMER_METHOD="cron"
223 | fi
224 | fi
225 | fi
226 |
227 | # Read the parameters:
228 | while getopts ":hud" opt; do
229 | case $opt in
230 | u ) fetch_new=t;;
231 | d ) debug=t;;
232 | \?|h ) help;;
233 | esac
234 | done
235 |
236 |
237 | # Get, and print, IP-addresses for all active interfaces based on $NetworkInterfaces
238 | # This is, as yet, Mac-only
239 | function PrintAllInterfaces()
240 | {
241 | #NSOfile="/tmp/NetworkServiceOrder_$$.txt"
242 | #networksetup -listnetworkserviceorder | grep -A 1 "^([0-9])\ " | grep "[a-z][0-9])$" | cut -d: -f2,3 | sed -e 's/, Device//g' -e 's/)//g' -e 's/^ //g' > $NSOfile
243 | NSO="$(networksetup -listnetworkserviceorder | grep -A 1 "^([0-9])\ " | grep "[a-z][0-9])$" | cut -d: -f2,3 | sed -e 's/, Device//g' -e 's/)//g' -e 's/^ //g')"
244 | #NetworkInterfaces="$(less $NSOfile | cut -d: -f2)"
245 | NetworkInterfaces="$(echo "$NSO" | cut -d: -f2)"
246 | # Ex: NetworkInterfaces=' en0 en1 en5 en2 bridge0'
247 | #echo "Available network interfaces: $NetworkInterfaces"
248 | FormatStringInterfaces="%-25s%-5s%-17s%-26s"
249 | # Thunderbolt Ethernet en1 130.235.120.242 fe80::1610:9fff:fece:fd95
250 | # 1234567890123456789012345678901234567890123456789012345678901234567890
251 | # 1 2 3 4 5 6 7
252 |
253 | NumActiveInterfaces="$(ifconfig | grep ":\ active$" | wc -l | awk '{print $1}')"
254 |
255 | # Print information about the various interfaces if there are more than one interface
256 | if [ $NumActiveInterfaces -gt 1 ]; then
257 | echo
258 | printf "${ESC}${BlackBack};${WhiteFont}mActive interfaces, in service order:${Reset}\n"
259 | IfNum=1
260 | for j in $NetworkInterfaces
261 | do
262 | IF="$(ifconfig $j 2>/dev/null | egrep "inet[6]?\ |status:\ ")"
263 | # Ex: IF='inet6 fe80::217:f2ff:fe04:4229%en1 prefixlen 64 scopeid 0x5 inet 192.168.1.69 netmask 0xffffff00 broadcast 192.168.1.255 status: active'
264 | if [ $? -eq 0 ]; then
265 | Active="$(echo $IF | egrep -o "status: [a-z0-9][^\ ]*" | awk '{print $2}')"
266 | if [ -z "${Active/active/}" ]; then
267 | IFName="$(echo "$NSO" | grep $j | cut -d: -f1)"
268 | # Ex: IFName='Ethernet 2'
269 | I4="$IFName ($j): $(echo $IF | egrep -o "inet\ [a-z0-9][^\ ]*" | awk '{print $2}')" # Ex: I4='Ethernet 2 (en1): 192.168.1.69'
270 | IP4_addr="$(echo $IF | egrep -o "inet\ [a-z0-9][^\ ]*" | awk '{print $2}')" # Ex: IP4_addr='192.168.50.201'
271 | #I6="$IFName ($j): $(echo $IF | egrep -o "inet6\ [a-z0-9][^\ ]*" | awk '{print $2}' | egrep -o "[^%]*")"
272 | I6="$IFName ($j): $(echo "$IF" | grep -Eo "^\s*inet6\ [a-z0-9:]*[^%]" | awk '{print $2}')" # Ex: I6='Wi-Fi (en0): fe80::ced:c35a:6cbe:6ab1'
273 | IP6_addr="$(echo "$IF" | grep -Eo "^\s*inet6\ [a-z0-9:]*[^%]" | awk '{print $2}')" # Ex: IP6_addr='fe80::ced:c35a:6cbe:6ab1'
274 | printf "${ESC}${WhiteBack};${BlackFont}m${FormatStringInterfaces}${Reset}\n" "${IfNum}. ${IFName}" "$j" "$IP4_addr" "$IP6_addr"
275 | let IfNum=( $IfNum + 1 )
276 | fi
277 | fi
278 | done
279 | fi
280 | # Clean up the $NSOfile
281 | #/bin/rm "$NSOfile" 2>/dev/null
282 | }
283 |
284 |
285 | # Basic settings:
286 | # PREFIX points to where the data files are stored.
287 | # IP_CACHE is a growing list of IP-addresses and their geographical location.
288 | # Since this is used by other scripts, it is not located in the OpenPorts directory
289 | if [ "$OS" = "Darwin" ]; then
290 | PREFIX="/Library/cs.lth.se/OpenPorts"
291 | IP_CACHE="/Library/cs.lth.se/ip_cache.txt"
292 | # GeoLookupDir is a dir where the geo lookup is stored
293 | GeoLookupDir="/Library/cs.lth.se/GeoLookup"
294 | #DEFAULT_INTERFACE="$(route get www.lu.se | grep interface | awk '{ print $2 }')"
295 | DEFAULT_INTERFACE="$(/usr/sbin/netstat -f inet -rn | grep "^default" | head -1 | awk '{print $NF}')"
296 | MY_IP_ADDRESS="$(ifconfig $DEFAULT_INTERFACE 2>/dev/null | grep "inet " | awk '{ print $2 }')"
297 | #DOMAIN="`ipconfig getpacket en0 | grep 'domain_name (string)' | awk '{ print $3 }'`"
298 | DOMAIN="$(hostname | cut -d\. -f2-7)"
299 | MTIME60m="-mtime -60m"
300 | MTIME120m="-mtime -120m"
301 | MTIME7d="-mtime -7d"
302 | elif [ "$OS" = "Linux" ]; then
303 | PREFIX="/usr/share/cs.lth.se/OpenPorts"
304 | IP_CACHE="/usr/share/cs.lth.se/ip_cache.txt"
305 | # GeoLookup is a dir where the geo lookup is stored
306 | GeoLookupDir="/usr/share/cs.lth.se/GeoLookup"
307 | DEFAULT_INTERFACE="$(/sbin/route | grep "^default" | awk '{ print $NF }')"
308 | MY_IP_ADDRESS="$(/sbin/ifconfig $DEFAULT_INTERFACE | grep "inet " | awk '{ print $2 }' | cut -d: -f2)"
309 | DOMAIN="$(dig +search +short -x $MY_IP_ADDRESS | cut -d\. -f2-8 | sed 's/\.$//g')"
310 | MTIME60m="-mmin -60"
311 | MTIME120m="-mmin +120"
312 | MTIME7d="-mtime -7"
313 | fi
314 | # BINDIR is where open_ports.sh should be
315 | BINDIR="/usr/local/bin"
316 | # OpenPortURL is where open_ports.sh and Countries.txt resides
317 | OpenPortsURL="http://fileadmin.cs.lth.se/cs/Personal/Peter_Moller/scripts"
318 | # NAT has content if we are on a private net (^192.168.|^172.16.|^10.) and empty otherwise
319 | NAT="$(echo $MY_IP_ADDRESS | egrep "^192.168.|^172.16.|^10.")"
320 | # ScriptName is simply the name of the script...
321 | ScriptName="$(basename $0)"
322 | # EXTERN stores the computers “external” address. It is checked hourly
323 | EXTERN="$PREFIX"/ExternIP.txt
324 | # ExternHistory stores a history of your external IP-addresses
325 | ExternHistory="$PREFIX"/ExternIP_history.txt
326 | # GeoLookupURL is where the Geo Lookup is performed
327 | GeoLookupURL="http://api.db-ip.com/addrinfo?addr="
328 | # GeoLookupKey is the key that is nessecary to actually perform geolookup
329 | GeoLookupKey="$(cat $PREFIX/apidb.key 2>/dev/null)"
330 | # FILE4 stores currently IPv4-ESTABLISHED connections. Generated every 2 minutes
331 | FILE4="$PREFIX"/ip4.txt
332 | # FILE6 stores currently IPv6-ESTABLISHED connections. Generated every 2 minutes
333 | FILE6="$PREFIX"/ip6.txt
334 | # FILE_LISTEN stores current LISTEN-connections. Generated every 2 minutes
335 | FILE_LISTEN="$PREFIX"/listen.txt
336 | # IP_LOCATE_CACHE is a temporary file that stores the geo location of the external address
337 | IP_LOCATE_CACHE="$PREFIX"/ip_locate_cache.txt
338 | # Empty file whose existence signals that the launchd-part of open_ports is NOT running
339 | LAUNCHD_FLAG="$PREFIX"/no_launchd
340 | # SoftwareUpdate-fil (temporary)
341 | SoftUpd=/tmp/swu.temp
342 | # String for printf (used to print ESTABLISHED-connections)
343 | Formatstring1="%-24s%-14s%-15s%2s%3s%-58s%-20s%-14s"
344 | Formatstring2="%-24s%-14s%-15s%2s%3s%-58s"
345 | # String for printf (used to print LISTEN-ports)
346 | FormatstringListen="%-6s%-6s%-18s%-15s%6s%2s%-17s%-15s"
347 | # UpdateMessage contains the message of weather an update is available och the checksum-check failed
348 | UpdateMessage=""
349 | # OP_LOGG is a log file where all things related to open_ports.sh (install and upgrades) are noted
350 | OP_LOGG="$PREFIX"/OpenPorts_log.txt
351 | # $CountryList is a list (stored locally, comes from http://www.worldatlas.com/aatlas/ctycodes.htm) of all the countries in the world
352 | CountryList="$PREFIX/Countries.txt"
353 | # IP_loggfile is used for debugging. It contains one line per IP lookup, along with PID and time stamp
354 | IP_loggfile=$PREFIX/IP_loggfil.txt
355 |
356 |
357 |
358 | # (Colors can be found at http://en.wikipedia.org/wiki/ANSI_escape_code, http://graphcomp.com/info/specs/ansi_col.html and other sites)
359 | Reset="\e[0m"
360 | ESC="\e["
361 | RES="0"
362 | BoldFace="1"
363 | ItalicFace="3"
364 | UnderlineFace="4"
365 | SlowBlink="5"
366 | BlackBack="40"
367 | RedBack="41"
368 | YellowBack="43"
369 | BlueBack="44"
370 | WhiteBack="47"
371 | BlackFont="30"
372 | RedFont="31"
373 | GreenFont="32"
374 | YellowFont="33"
375 | BlueFont="34"
376 | CyanFont="36"
377 | WhiteFont="37"
378 |
379 | # Reset all colors
380 | BGColor="$RES"
381 | Face="$RES"
382 | FontColor="$RES"
383 |
384 | # Create LSOF_PATH
385 | if [ -x /usr/sbin/lsof ]; then
386 | LSOF_PATH="/usr/sbin"
387 | elif [ -x /usr/bin/lsof ]; then
388 | LSOF_PATH="/usr/bin"
389 | fi
390 |
391 |
392 | # =================================================================================================================
393 | # =================================================================================================================
394 | # ================================ D A T A I S G E N E R A T E D H E R E ==================================
395 | # =================================================================================================================
396 | # =================================================================================================================
397 | #
398 | # Create in-data (if run through launchd, $USER = nil or root) and then stop
399 | #
400 | if [ "$USER" = "root" -o -z "$USER" ]; then
401 | if [ -z "$DEFAULT_INTERFACE" ] ; then
402 | echo "You have no IP-address. Exiting"
403 | exit 1
404 | fi
405 |
406 |
407 | printf "Generating datafiles..."
408 |
409 | # Check that the base files exist (otherwise create them and set access rights)
410 | # (need to use cut to not see extended attributes that will mess up the test)
411 | if [ ! "$(ls -ls "$FILE4" 2> /dev/null | awk '{ print $2 }' | cut -c1-10)" = "-rw-rw-rw-" ]; then
412 | mkdir -p $(dirname "$FILE4") 2> /dev/null
413 | [[ "$OS" = "Darwin" ]] && chgrp -R staff `dirname "$FILE4"`
414 | chmod 775 $(dirname "$FILE4")
415 | touch "$FILE4" "$FILE6" "$IP_CACHE" "$IP_LOCATE_CACHE" "$EXTERN" "$FILE_LISTEN"
416 | #chmod 666 `dirname "$FILE4"`/??*
417 | fi
418 |
419 | # Check the external IP-adress:
420 | # A) has it been updated recently (≤ 60 minutes)
421 | # B) is it a reasonably address
422 | # C) does it differ from the previously stored $EXTERN
423 | # D) if so, remove 127.0.0.1 from $GeoLookupDir (since it's not correct)
424 | if [ -z "$(find $EXTERN -type f ${MTIME60m} 2> /dev/null)" ]; then
425 | #echo "$(curl http://tejji.com/ip/my-ip-address.aspx 2> /dev/null | grep -A 1 '' | tail -1 | sed -E 's/<[/]?span[^>]*>//g' | awk '{print $1}')" > /tmp/slaskextern
426 | #SlaskExtern="$(curl http://tejji.com/ip/my-ip-address.aspx 2> /dev/null | grep -A 1 '
' | tail -1 | sed -E 's/<[/]?span[^>]*>//g' | awk '{print $1}' | tr -d '\r\n')"
427 | # SlaskExtern replaced with simplier call thanks to great feedback from a User op open_ports! :-) I keep the old function for future reference.
428 | SlaskExtern="$(curl http://ipecho.net/plain 2> /dev/null)"
429 | [ "$debug" = "t" ] && echo "$(date +%F" "%T); #479; $$; User=\"$USER\"; curl to ipecho.net for external address" >> $IP_loggfile
430 | # Check to see if this is an IP-address (it should be an empty string after sed if it is)
431 | if [ -z "$(echo $SlaskExtern | sed 's/[0-9\.]//g')" ]; then
432 | # If it's different from the stored one; we have moved and need to update $EXTERN
433 | # and store the external address along with a timestamp in $ExternHistory
434 | if [ ! "$SlaskExtern" = "$(less $EXTERN 2>/dev/null)" ]; then
435 | IP="$SlaskExtern"
436 | if [ -r "${GeoLookupDir}/${IP}.txt" ]; then
437 | GetCityCountry $IP
438 | else
439 | PerformGeoLookup $IP
440 | fi
441 | # echo "Add to history file"
442 | echo "$IP:$Country:$City:`date +%Y-%m-%d,\ %H.%M`" >> "$ExternHistory"
443 | echo "$SlaskExtern" > "$EXTERN"
444 | # Also, create a new file for 127.0.0.1 (since it will be a new one)
445 | PerformGeoLookup "$(less $EXTERN)"
446 | echo "$City:$Country" > "${GeoLookupDir}/127.0.0.1.txt"
447 | # rm $"{GeoLookupDir}/127.0.0.1" 2>/dev/null
448 | else
449 | # Touch $EXTERN so it will not check the external address every 2 minutes
450 | touch "$EXTERN"
451 | fi
452 | fi
453 | fi
454 |
455 |
456 | # Create data for ESTABLISHED:
457 | # Previous capture line. Still here for reference:
458 | # lsof +c 0 -i 4 -n | grep EST | grep -v "\->127.0.0.1" | sort -f -k 1,1 | cut -d\( -f1 | awk '{ print $1" "$3" "$9 }' | sed 's/\ [[:digit:]].*-\>/\ /g' | sed 's/:/\ /g' | sort -f | uniq -c > $FILE4
459 | if [ "$OS" = "Darwin" ]; then
460 | $LSOF_PATH/lsof +c 0 -i 4 -n | grep EST | sort -f -k 1,1 | cut -d\( -f1 | awk '{ print $1" "$3" "$9 }' | sed 's/\ [[:digit:]].*-\>/\ /g' | sed 's/:/\ /g' | sort -f | uniq -c > $FILE4
461 | # “sanitize” the output by replacing long strings with shorter ones. This started in OS X 10.11 “El Capitan”
462 | # The following strings are inteded to be cought:
463 | # - 'com.apple.WebKit.*'
464 | # - 'com.apple.Safari.*'
465 | # - '2BUA8C4S2C.com.*'
466 | sed -e 's/com.apple.//' -e 's/2BUA8C4S2C.com[a-z.]* /1Password /' -i .bak $FILE4
467 |
468 |
469 | # The following line is replaced by the one next below after a bug report from Roman Weber. Have not had time to check i thoroughly, though, so it's still here:
470 | #$LSOF_PATH/lsof +c 0 -i 6 -n | grep EST | grep -v "\->\[\:\:$MY_IP_ADDRESS\]" | sort -f -k 1,1 -k 2,2 | awk '{ print $1" "$3" "$9 }' | sed -E "s/\ \[::[[:digit:]].*-\>\[::/\ /g" | sed "s/\]:/\ /g" | sort -f | uniq -c > $FILE6
471 | # Something is definetley not right here. Another fix and, I guess, primarily waiting for a couple of 'real' IPv6-catches...
472 | #$LSOF_PATH/lsof +c 0 -i 6 -n | grep EST | grep -v "\->\[\:\:$MY_IP_ADDRESS\]" | sort -f -k 1,1 -k 2,2 | awk '{ print $1" "$3" "$9 }' | sed -E "s/\ \[.*-\>\[/\ /g" | sed "s/\]:/\ /g" | sort -f | uniq -c > $FILE6
473 | # $LSOF_PATH/lsof +c 0 -i 6 -n | grep EST | sort -f -k 1,1 | cut -d\( -f1 | awk '{ print $1" "$3" "$9 }' | sed 's/\ [[:digit:]].*-\>/\ /g' | sed 's/:/\ /g' | sort -f | uniq -c > $FILE6
474 | $LSOF_PATH/lsof +c 0 -i 6 -n | grep EST | sort -f -k 1,1 | cut -d\( -f1 | awk '{ print $1" "$3" "$9 }' | sed -e 's/ \[[^-]*->/ /g' -e 's/]:/] /g' | sort -f | uniq -c > $FILE6
475 | elif [ "$OS" = "Linux" ]; then
476 | $LSOF_PATH/lsof +c 0 -i 4 -n | grep EST | sort -f -k 1,1 | cut -d\( -f1 | awk '{ print $1" "$3" "$9 }' | sed 's/\ [[:digit:]].*->/\ /g' | sed 's/:/\ /g' | sort -f | uniq -c > $FILE4
477 | # Have not had access to a linux machine running IPv6 so for Linux we simply skip IPv6 for the time being
478 | ## $LSOF_PATH/lsof +c 0 -i 6 -n | grep EST | grep -v "->\[\:\:$MY_IP_ADDRESS\]" | sort -f -k 1,1 -k 2,2 | awk '{ print $1" "$3" "$9 }' | sed -E "s/\ \[::[[:digit:]].*->\[::/\ /g" | sed "s/\]:/\ /g" | sort -f | uniq -c > $FILE6
479 | fi
480 | # For future development: the ip6-lines to be grep'ed *should* look like this:
481 | # lsof -n -i 6 | grep EST
482 | # Screen 56128 peterm 6u IPv6 0x169caf80 0t0 TCP [fde2:ccd9:7a6b:7089:21e:52ff:fe83:b033]:51199->[fd58:97aa:2e6:277d:217:f2ff:fe04:4228]:vnc-server (ESTABLISHED)
483 | # (captured ARD-session home)
484 | # This is how it looks in the other end:
485 | # AppleVNCS 56767 peterm 11u IPv6 0x09646d10 0t0 TCP [fd58:97aa:2e6:277d:217:f2ff:fe04:4228]:vnc-server->[fde2:ccd9:7a6b:7089:21e:52ff:fe83:b033]:51199 (ESTABLISHED)
486 |
487 |
488 | # Create data for LISTEN:
489 | if [ "$OS" = "Darwin" ]; then
490 | $LSOF_PATH/lsof +c 0 -i 4 -n | grep LISTEN | sort -f -k 1,1 | cut -d\( -f1 | awk '{ print "4 - "$1" "$3" "$9 }' | sed 's/:/\ /g' | sed 's/\ [[:digit:]]\{2,5\}$/\ anonymous_port/g' | uniq > /tmp/slask
491 | $LSOF_PATH/lsof +c 0 -i 6 -n | egrep LISTEN | awk '{ print "- 6 "$1" "$3" "$9 }' | sort -f | sed 's/\ \[.*\]/\ \*/g' | sed 's/:/\ /g' | sed 's/\ [[:digit:]]\{2,5\}$/\ anonymous_port/g' | uniq >> /tmp/slask
492 | # Clean '1Password'
493 | sed -e 's/2BUA8C4S2C.com[a-z.]* /1Password /' -i .bak /tmp/slask
494 | elif [ "$OS" = "Linux" ]; then
495 | $LSOF_PATH/lsof +c 0 -i 4 -n | grep LISTEN | sort -f -k 1,1 | cut -d\( -f1 | awk '{ print "4 - "$1" "$3" "$9 }' | sed 's/:/\ /g' | sed 's/\ [[:digit:]]\{2,5\}$/\ anonymous_port/g' | uniq > /tmp/slask
496 | $LSOF_PATH/lsof +c 0 -i 6 -n | egrep LISTEN | awk '{ print "- 6 "$1" "$3" "$9 }' | sort -f | sed 's/\ \[.*\]/\ \*/g' | sed 's/:/\ /g' | sed 's/\ [[:digit:]]\{2,5\}$/\ anonymous_port/g' | uniq >> /tmp/slask
497 | fi
498 | # Sort by application:
499 | less /tmp/slask | sort -f -k 3 > "$FILE_LISTEN"
500 | # Add a line at the end so that we do not forget the last line during printout
501 | echo "" >> "$FILE_LISTEN"
502 | # One can check the IP-address with this sed-line: sed 's/\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}:.\{2,15\}->//g' (possible future development)
503 |
504 | # Create a file whose existence tells if the launchd-part of open_ports is running (otherwise warn the user)
505 | if [ "$TIMER_METHOD" = "launchd" ]; then
506 | if [ -z "`launchctl list | grep 'se.lth.cs.open_ports'`" ]; then
507 | touch "$LAUNCHD_FLAG"
508 | else
509 | /bin/rm -f "$LAUNCHD_FLAG" 2> /dev/null
510 | fi
511 | fi
512 |
513 | # On Mac OS X: see if there is any system software updates
514 | # Check this every three hours
515 | if [ "$OS" = "Darwin" ]; then
516 | if [ -z "`find $SoftUpd -type f -mtime -3h 2> /dev/null`" ]; then
517 | softwareupdate -l 1> "$SoftUpd" 2> /dev/null
518 | chmod 644 "$SoftUpd" 2> /dev/null
519 | fi
520 | fi
521 |
522 | # Make sure there is a GeoLookupDir and it has usable permissions.
523 | # This could most probably be made much better
524 | [[ -d "$GeoLookupDir" ]] || mkdir $GeoLookupDir 2>/dev/null
525 | chmod 777 "$GeoLookupDir" 2> /dev/null
526 | chmod 666 "$GeoLookupDir/*" 2> /dev/null
527 |
528 | # Make sure the Countries-file exist. Fetch it otherwise
529 | # This can probably be removed in 2015
530 | if [ ! -f "$CountryList" ]; then
531 | curl -s -f -e "$ScriptName ver:$VER" -o /tmp/Countries.txt "$OpenPortsURL"/Countries.txt 2>/dev/null
532 | curl -s -f -e "$ScriptName ver:$VER" -o /tmp/Countries.txt.sha1 "$OpenPortsURL"/Countries.txt.sha1 2>/dev/null
533 | ERR=$?
534 | if [ "$ERR" -eq 0 ] ; then
535 | if [ "$(openssl sha1 /tmp/Countries.txt | awk '{ print $2 }')" = "$(less /tmp/Countries.txt.sha1)" ]; then
536 | /bin/mv /tmp/Countries.txt "$CountryList"
537 | /bin/rm /tmp/Countries.txt.sha1 2>/dev/null
538 | echo "$(date): The file \"Countries.txt\" was installed" >> "$OP_LOGG"
539 | fi
540 | else
541 | echo "$(date): The \"Countries.txt\" could not be fetched (Err: \"${ERR}\")" >> "$OP_LOGG"
542 | fi
543 | fi
544 |
545 |
546 | # Clean up leftover-files in /tmp
547 | /bin/rm -f /tmp/"$ScriptName" /tmp/"$ScriptName".sha1 2>/dev/null
548 |
549 | printf " Done! (View data by running the script as any other user)\n"
550 |
551 | exit 0
552 | fi
553 | # =================================================================================================================
554 | # =================================================================================================================
555 | # =============================== E N D O F D A T A G E N E R A T I O N =================================
556 | # =================================================================================================================
557 | # =================================================================================================================
558 | #
559 | #
560 | # Everything below is run by the user
561 |
562 |
563 | # Clean the GeoLocate cache for old entries every 7 days
564 | if [ -z "$(find $BINDIR/open_ports.sh -type f ${MTIME7d} 2> /dev/null)" ]; then
565 | CleanGeoLocate
566 | # touch the script so we come to this part of the script ever again
567 | touch "$BINDIR/$ScriptName" 2>/dev/null
568 | fi
569 |
570 |
571 | # ----------------------------------------------------------------------------------------------------
572 | #
573 |
574 | # Print warnings if something is not right
575 |
576 | # Check if there is any data file: warn the user and quit otherwise
577 | if [ ! -f "$FILE4" ]; then
578 | printf "${ESC}${RedFont}mWARNING: No datafile! Run the command as \"root\" to generate data! (Or install the \"launchd\"-component)$Reset\n\nWill now exit!\n"
579 | exit 0
580 | fi
581 |
582 | # Check to see if the launchd-part is running. Warn the user otherwise
583 | if [ "$TIMER_METHOD" = "launchd" ]; then
584 | if [ -f "$LAUNCHD_FLAG" ]; then
585 | printf "${ESC}${RedFont}mWARNING: The \"launchd\"-component of \"open_ports.sh\" is NOT RUNNING!!!\n\n$Reset"
586 | fi
587 | elif [ "$TIMER_METHOD" = "systemd" ]; then
588 | if [ "$(systemctl is-active open-ports.timer)" != "active" ]; then
589 | printf "${ESC}${RedFont}mWARNING: The \"systemd\"-component of \"open_ports.sh\" is NOT RUNNING!!!\n\n$Reset"
590 | fi
591 | fi
592 |
593 | # Se that the datafiles are created within the last hour. Otherwise tell the user about it!
594 | if [ -z "$(find $FILE4 -type f ${MTIME60m} 2> /dev/null)" ]; then
595 | if [ "$TIMER_METHOD" = "launchd" ]; then
596 | printf "${ESC}${RedFont}mWARNING: The datafile is older than 1 hour; make sure the \"launchd\"-component (\"se.lth.cs.open_ports\", located in \"/Library/LaunchDaemons\")\n$Reset"
597 | elif [ "$TIMER_METHOD" = "systemd" ]; then
598 | printf "${ESC}${RedFont}mWARNING: The datafile is older than 1 hour; make sure the \"systemd\"-component (\"open-ports.timer\", located in \"/etc/systemd/system\")\n$Reset"
599 | fi
600 | printf "${ESC}${RedFont}mis working properly! The information presented here is not current!!$Reset\n\n\n"
601 | fi
602 |
603 | # If we don't have an IP-address ($DEFAULT_INTERFACE = "") warn the user!!
604 | if [ -z "$DEFAULT_INTERFACE" ]; then
605 | printf "${ESC}${RedFont}mWARNING: No IP-address detected!!!\n\n$Reset"
606 | fi
607 |
608 | # Find out if is IPv6 is configured
609 | if [ -z "$(/sbin/ifconfig $DEFAULT_INTERFACE | grep inet6)" ]; then
610 | IPv6="f"
611 | else
612 | IPv6="t"
613 | fi
614 |
615 | # End print warnings
616 | #
617 | # ----------------------------------------------------------------------------------------------------
618 |
619 |
620 | # Prepare what is to be presented regarding the IP-address (if we are behind a NAT it should be prented)
621 | if [ "$(less $EXTERN)" = "$MY_IP_ADDRESS" ]; then
622 | IP_ADDRESS_Display="$MY_IP_ADDRESS"
623 | else
624 | IP_ADDRESS_Display="NAT: $MY_IP_ADDRESS / $(less $EXTERN)"
625 | fi
626 |
627 | # Find out which distro we are running
628 | # On Mac OS X, use the command "sw_vers"
629 | # On linux, use the command "lsb_release" if available, otherwise use the file "/etc/issue"
630 | if [ "$OS" = "Darwin" ]; then
631 | SW_VERS="$(sw_vers | grep ProductName | cut -d: -f2 | tr -d "\t") $(sw_vers | grep ProductVersion | awk '{print $2}' | tr '\n' ' ')"
632 | # Find out if it's a server
633 | # First step: does the name fromsw_vers include "server"?
634 | if [ -z "$(echo "$SW_VERS" | grep -i server)" ]; then
635 | # If not, it may still be a server. Beginning with OS X 10.8 all versions include the command serverinfo:
636 | serverinfo --software 1>/dev/null
637 | # Exit code 0 = server; 1 = NOT server
638 | ServSoft=$?
639 | if [ $ServSoft -eq 0 ]; then
640 | # Is it configured?
641 | serverinfo --configured 1>/dev/null
642 | ServConfigured=$?
643 | if [ $ServConfigured -eq 0 ]; then
644 | SW_VERS="$SW_VERS ($(serverinfo --productname) $(serverinfo --shortversion))"
645 | else
646 | SW_VERS="$SW_VERS ($(serverinfo --productname) $(serverinfo --shortversion) - unconfigured)"
647 | fi
648 | fi
649 | fi
650 | elif [ "$OS" = "Linux" ]; then
651 | if [ -x /bin/lsb_release ]; then
652 | SW_VERS="$(lsb_release -a 2> /dev/null | grep Description | cut -d: -f2 | sed 's/^\t*//g')"
653 | elif [ -f /etc/issue ]; then
654 | SW_VERS="$(grep -v "^$" /etc/issue | head -1 | cut -d\\ -f1 | head -1)"
655 | else
656 | SW_VERS="Unknown Linux distribution"
657 | fi
658 | fi
659 |
660 |
661 | #
662 | # Print the head
663 |
664 | # First, print if there is an update for the script available
665 | printf "$UpdateMessage"
666 | printf "${ESC}${BlackBack};${WhiteFont}mHostname:${ESC}${WhiteBack};${BlackFont}m $(hostname) ($IP_ADDRESS_Display) ${Reset} ${ESC}${BlackBack};${WhiteFont}mRunning:${ESC}${WhiteBack};${BlackFont}m $SW_VERS ${Reset} ${ESC}${BlackBack};${WhiteFont}mUptime:${ESC}${WhiteBack};${BlackFont}m $(uptime | cut -d, -f1 | sed -E 's/^.*up\ //g') ${Reset}\n"
667 |
668 | # If a Mac, print information about all configured interfaces
669 | [ "$OS" = "Darwin" ] && PrintAllInterfaces
670 |
671 | echo
672 | # System Software Update, Mac OS X:
673 | # Report the available software updates (from the file/tmp/swu.temp, generated by this script)
674 | #
675 | # That file typically contains this:
676 | # Software Update Tool
677 | # Copyright 2002-2009 Apple
678 | #
679 | # Software Update found the following new or updated software:
680 | # * MacOSXUpd10.6.5-10.6.5
681 | # Mac OS X Update (10.6.5), 505193K [recommended] [restart]
682 | # * iTunesX-10.1.1
683 | # iTunes (10.1.1), 91023K [recommended]
684 | # * XcodeUpdate-3.2.5
685 | # Xcode Update (3.2.5), 604086K [recommended]
686 | # * Safari5.0.3SnowLeopard-5.0.3
687 | # Safari (5.0.3), 38316K [recommended] [restart]
688 | # * AirPortUtility-5.5.2
689 | # AirPort Utility (5.5.2), 11990K [recommended]
690 |
691 | # From this we will cut away everything but this:
692 | # Mac OS X Update (10.6.5) [restart]
693 | # iTunes (10.1.1)
694 | # Xcode Update (3.2.5)
695 | # Safari (5.0.3) [restart]
696 | # AirPort Utility (5.5.2)
697 | if [ "$OS" = "Darwin" ]; then
698 | if [ "$(grep 'Software Update found the following new or updated software' $SoftUpd)" ]; then
699 | printf "${ESC}${BoldFace};${BlackFont};${YellowBack}mThe following software update is available:${Reset}\n${ESC}${YellowFont}m"
700 | less "$SoftUpd" | egrep -v "^Software Update Tool|^Copyright 2002-2009 Apple|^$" | awk '
701 | /^\ *\*\ / {
702 | record="t";next;
703 | }
704 | record == "t" { gsub("^[ \t]*","");gsub(", [0-9]*K \\[[^\\]]*\\]","");print "• "$0;record="f";next}'
705 | printf "${Reset}\n"
706 | fi
707 | fi
708 |
709 | # End print of the head
710 |
711 | # |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
712 | # Print the ETSABLISHED-files
713 | for i in 4 6
714 | do
715 | if [ "$i" = "4" ]; then
716 | exec 4<"$FILE4"
717 | else
718 | exec 6<"$FILE6"
719 | fi
720 |
721 | # Prepare the date/time-string. Example: “18 Sep 10:29”
722 | [[ "$OS" = "Darwin" ]] && DATE=$(ls -ls $(dirname "$FILE4"/ip"$i".txt) | awk '{ print $7" "$8" "$9 }')
723 | [[ "$OS" = "Linux" ]] && DATE=$(ls -ls --time-style=+%Y-%m-%d\ %H:%M $(dirname "$FILE4"/ip"$i".txt) | awk '{ print $7" "$8 }')
724 | printf "${ESC}${BoldFace}mEstablished IPv$i-connections:$Reset ($DATE) $(if [ "$i" = "4" ]; then printf "${ESC}${ItalicFace}m(Explanation: Normal$Reset, ${ESC}${GreenFont};${ItalicFace}mSafe protocol$Reset, ${ESC}${CyanFont};${ItalicFace}mAmbiguous DNS$Reset, ${ESC}${RedFont};${ItalicFace}mNo DNS-name$Reset, ${ESC}${RedBack};${WhiteFont};${ItalicFace}mUser is root$Reset${ESC}${ItalicFace}m)$Reset"; fi)\n"
725 | if [ "$IPv6" = "f" -a "$i" -eq 6 ]; then
726 | printf "${ESC}${ItalicFace};${YellowFont}mIPv6 is not configured for interface \"${DEFAULT_INTERFACE}\"$Reset"
727 | else
728 | echo
729 | # Print different headers if $PREFIX/$GeoLookupKey exist or not
730 | if [ -n "$GeoLookupKey" ]; then
731 | printf "${ESC}${UnderlineFace};${YellowFont}m${Formatstring1}${Reset}\n" "Program" "Port" "User" "#" " " "Hostname $(if [ ! "$DOMAIN" = "" ]; then echo "[.$DOMAIN]"; fi)" "Country" "City"
732 | else
733 | printf "${ESC}${UnderlineFace};${YellowFont}m${Formatstring2}${Reset}\n" "Program" "Port" "User" "#" " " "Hostname $(if [ ! "$DOMAIN" = "" ]; then echo "[.$DOMAIN]"; fi)"
734 | fi
735 | if [ -s "$PREFIX/ip$i.txt" ]; then
736 | while read -u $i COUNT PROGRAM USERR IP PORT
737 | # Exmple lines:
738 | # IPv4: 1 2BUA8C4S2C.com. peterm 127.0.0.1 49206
739 | # IPv6: 1 Screen\x20Sharing peterm 192.168.1.99:63835->130.235.16.211:rfb
740 | do
741 | # Zero the colors:
742 | BGColor="$RES"
743 | Face="$RES"
744 | FontColor="$RES"
745 |
746 | # lsof +c 0 replaces " " in application names with "x20"; change back!
747 | PROGRAM="$(echo $PROGRAM | sed 's/x20/\ /g')"
748 | # If the text is too wide, shorten it
749 | if [ $(echo $PROGRAM | wc -c) -gt 23 ]; then
750 | PROGRAM="$(echo $PROGRAM | sed 's/x20/\ /g' | cut -c -20)..."
751 | fi
752 |
753 | # Find out the hostname for $IP. Cut of the trailing dot
754 | # Gives: $HOSTNAME
755 | # Also gives PrivateAddress="Yes" if it's a private address (192.168.*.*, 172.16.*.*, 10.*.*.*, 169.254.*.*)
756 | # (REMOVED) VERY DIRTY: "$(echo $IP | cut -d: -f1)"
757 | GetDNS "$IP"
758 | # GetDNS "$(echo $IP | cut -d: -f1)"
759 |
760 | # Find the geo location (also deal with localhost!)
761 | # If $IP exist in $GeoLookupDir - get the country and city right away
762 | # otherwise,
763 | # if IP is 127.0.0.1
764 | # AND we are beind a NAT-router (MY_IP_ADDRESS is in the {192.168|172.16|10}-series);
765 | # find the external address with whatsmyip.com and store it along with country/city
766 | # otherwise
767 | # look up the geodata for the default address for the computer
768 | # otherwise
769 | # look up the IP address and store in the temporary cache
770 | # get the country and city and store in $IP_CACHE
771 | # (DIRT REMOVED) VERY DIRTY: "$(echo $IP | cut -d: -f1)"
772 | if [ -r "${GeoLookupDir}/${IP}.txt" ]; then
773 | GetCityCountry $IP
774 | else
775 | if [ "$IP" = "127.0.0.1" ]; then
776 | if [ -n "$NAT" ]; then
777 | PerformGeoLookup "$(less $EXTERN)"
778 | echo "$City:$Country" > "${GeoLookupDir}/${IP}.txt"
779 | else
780 | PerformGeoLookup $MY_IP_ADDRESS
781 | fi
782 | else
783 | # PerformGeoLookup $IP
784 | PerformGeoLookup "$(echo $IP | cut -d: -f1)"
785 | fi
786 | fi
787 |
788 | # Set the colors:
789 | # If user is root - red background and white text!
790 | if [ "$USERR" = "root" ]; then
791 | BGColor="$RedBack"
792 | FontColor="$WhiteFont"
793 | fi
794 | # If it's a safe protocol - green text
795 | if [ ! -z "$(echo $PORT | egrep 'ssh|https|imaps|smtps|scp|sftp')" -o ! -z "$(echo $PROGRAM | egrep 'sshd')" ]; then
796 | FontColor="$GreenFont"
797 | fi
798 | # No DNS-name AND we are not in a home environment - red text and explain
799 | if [ -n "$(echo "$HOSTNAME" | grep 'DNS timeout')" -a -z "$NAT" ]; then
800 | #HOSTNAME="$IP can’t be found in reverse-lookup"
801 | FontColor="$RedFont"
802 | fi
803 | # many answers to the reverse DNS lookup? Blue text and explain
804 | # Otherwise: print
805 | if [ "$(echo $HOSTNAME | wc -w)" -gt "1" -a -z "$(echo $HOSTNAME | grep 'DNS timeout')" -a "$PrivateAddress" = "No" ]; then
806 | FontColor="$CyanFont"
807 | HOSTN="$IP = \"$(echo $HOSTNAME | awk '{ print $1 }')\" and `echo $(( $(echo $HOSTNAME | wc | awk '{ print $2 }') - 1 ))` more names"
808 | HOSTNAME="$HOSTN"
809 | fi
810 | # If background is red AND text is red? Blink with white text!
811 | if [ "$BGColor" = "41" -a "$FontColor" = "31" ]; then
812 | FontColor="$WhiteFont"
813 | Face="$SlowBlink"
814 | fi
815 | # Print the line!
816 | if [ -n "$GeoLookupKey" ]; then
817 | printf "${ESC}${Face};${BGColor};${FontColor}m$Formatstring1$Reset\n" "$PROGRAM" "$PORT" "$USERR" "$COUNT" " " "${HOSTNAME//.$DOMAIN}" "$Country" "$City"
818 | else
819 | printf "${ESC}${Face};${BGColor};${FontColor}m$Formatstring2$Reset\n" "$PROGRAM" "$PORT" "$USERR" "$COUNT" " " "${HOSTNAME//.$DOMAIN}"
820 | fi
821 | done
822 | else
823 | echo "No established IPv$i-connections"
824 | fi
825 | fi
826 | echo
827 | echo
828 | done
829 |
830 | # End print of ESTABLISHED
831 | # |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
832 |
833 |
834 |
835 | # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
836 | # Print the LISTEN-file
837 | LastIPv4=""
838 | LastIPv6=""
839 | LastProgram=""
840 | LastUser=""
841 | LastRange=""
842 | LastPort=""
843 | exec 5<"$FILE_LISTEN"
844 | if [ -s "$FILE_LISTEN" ]; then
845 | [[ "$OS" = "Darwin" ]] && DATE=$(ls -ls "$FILE_LISTEN" | awk '{ print $7" "$8" "$9 }')
846 | [[ "$OS" = "Linux" ]] && DATE=$(ls -ls --time-style=+%Y-%m-%d\ %H:%M "$FILE_LISTEN" | awk '{ print $7" "$8 }')
847 | printf "\n\n${ESC}${BoldFace}mListening ports:$Reset ($DATE)\n\n"
848 | printf "${ESC}${UnderlineFace};${YellowFont}m$FormatstringListen$Reset\n" "IPv4" "IPv6" "Program" "User" "Port#" " " "PortName" "Servicerange"
849 | while read -u 5 IPv4 IPv6 PROGRAM USERR RANGE PORT
850 | do
851 | # Reset the colors:
852 | BGColor="$RES"
853 | Face="$RES"
854 | FontColor="$RES"
855 |
856 | # lsof +c 0 replaces " " in application names with "x20"; change back!
857 | PROGRAM="$(echo $PROGRAM | sed 's/x20/\ /g')"
858 | # If the text is too wide, shorten it
859 | if [ $(echo $PROGRAM | wc -c) -gt 16 ]; then
860 | PROGRAM="$(echo $PROGRAM | sed 's/x20/\ /g' | cut -c -15)..."
861 | fi
862 | #PROGR=`echo $PROGRAM | sed 's/x20/\ /g'`
863 | # If the lines are the same: do nothing more than to set both 4 and 6 when it is to be printed the next turn around
864 | if [[ "$LastProgram" = "$PROGRAM" && "$LastUser" = "$USERR" && "$LastPort" = "$PORT" && "$LastRange" = "$RANGE" ]]; then
865 | export LastIPv4="4"
866 | export LastIPv6="6"
867 | else
868 | # This turn is will be printed
869 |
870 | # If LastProgram is NOT empty (then assume the other are as well; first turn around - do not print!)
871 | # the choose colors
872 | if [ ! -z "$LastProgram" ]; then
873 | # If user is root - red background and white text!
874 | if [ "$LastUser" = "root" ]; then
875 | BGColor="$RedBack"
876 | FontColor="$WhiteFont"
877 | fi
878 | # Safe protocol - green text
879 | if [ ! -z "`echo $LastPort | egrep 'ssh|https|imaps|smtps|scp|sftp'`" -o ! -z "`echo $LastProgram | egrep 'sshd'`" ]; then
880 | FontColor="$GreenFont"
881 | fi
882 | # Print!!
883 | printf "${ESC}${BGColor};${FontColor}m$FormatstringListen$Reset\n" "$LastIPv4" "$LastIPv6" "$LastProgram" "$LastUser" "`grep "^$LastPort\b" /etc/services | head -1 | awk '{ print $2 }' | cut -d/ -f1`" " " "`echo $LastPort | sed 's/_/\ /g'`" "$LastRange"
884 | fi
885 | LastIPv4="$IPv4"
886 | LastIPv6="$IPv6"
887 | fi
888 | LastProgram="$PROGRAM"
889 | LastUser="$USERR"
890 | LastPort="$PORT"
891 | LastRange="$RANGE"
892 | done
893 | else
894 | echo "No ports open for listening"
895 | fi
896 |
897 | # End print of LISTEN
898 | # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
899 |
900 | exit 0
901 |
--------------------------------------------------------------------------------