ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I'm trying to write a script to list all open ports in the MINIUNPND chain in iptables and use the procotol, port and destination ip to open ports on another router using upnpc.
Here is the output of iptables -L MINIUPNPD
This didn't work so i had to run the loop 3 times, once for each array i wanted to fill
Code:
index=0
ips="tmp.txt"
while read line ; do
MYDEST[$index]=$(awk -v t="$line" '{print $5}')
index=$(($index+1))
done < $ips
index=0
ips="tmp.txt"
while read line ; do
s=$(awk -v t="$line" '{print $7}')
MYPORT[$index]=$s
index=$(($index+1))
done < $ips
index=0
ips="tmp.txt"
while read line ; do
MYPROT[$index]=$(awk -v t="$line" '{print $6}')
index=$(($index+1))
done < $ips
echo "Destinations are"
echo "${MYDEST[*]}"
echo "Protols are"
echo "${MYPROT[*]}"
echo "Ports are"
echo "${MYPORT[*]}"
No matter what i do i cant seem to remove the first 4 characters from the MYPROT array to leave only the digits. Also i cant seem to read the array back???
I thought it would simply be a loop reading each line and passing the fields in variables, executing upnpc commands i need then moving to the next line of the file until it reached the EOF
Someone please help as i have spent 2 days trying to get this to work.
You set the awk variable "t", but then never use it in the command. I think you want to do something like echo "$line" | awk ... instead.
I don't have time to test it out now, but I'd probably get awk to print all three fields at once, and use that to set an intermediate array. Then use that array to set your final array variables. Something like this:
Wow Thank you theNbomr (rod) You are a star!
That script works lovely! Any chance you can please explain HOW it works? I understand most if it except the syntax of "(awk 'NF == 7 { print $5, $6, $7 }' /tmp/LQUrbanPykey.iptables)".
Its the syntax of operators i get confused with in bash!
Now all i have to do is get this script run by cron at regular intervals or whenever the MINIPNPD chain of iptables changes!
Oh and grail your script cause me to get a syntax error
[CODE]
iptables -L | awk 'NR > 2{sub(/.*:/,"",$7),cmd = "upnpc -r -a "$5" "$7" "$6;print | cmd}'
awk: NR > 2{sub(/.*:/,"",$7),cmd = "upnpc -r -a "$5" "$7" "$6;print | cmd}
awk: ^ syntax error
[CODE]
I think i understand now! NF==7 states it only looks at lines with EXACTLY 7 fields yes?
Just the syntax of the
Code:
c=$(echo $c | cut -d: -f2)
That part chops off the leading 'dpt:' part of the last field. It uses cut to break the string into fields delimited by ':' ( -d: ), and takes the second field ( -f2 ) from the result.
grails effort trumps mine, once you get it working; doesn't use a temp file.
The awk part does only look at records with exactly 7 fields.
It would take me a degree in BASH to work out HOW Grails script works! Your script is more at my level, ONCE i get into my head how the syntax of bash works a bit more. It all seemed so easy laid out on paper in pseudo code!
Anyways here is my completed script, i have added some extra variables to avoid upnpc failing to discover the remote router and to set the destination to the local IP of the local ClearOS gateway
Code:
#!/bin/bash
#
# ****************************************************
# * Remote router upnp Port opener ver 1.01 *
# * *
# * Written by K. Winstanley 29/03/11 *
# * *
# * credit to LinuxQuestions Forum users *
# * http://www.linuxquestions.org *
# * *
# * This script reads the MINIUPNPD chain of iptables*
# * containing all upnp opened ports on the local *
# * ClearOS gateway and repeats these port mappings *
# * on the upstream router using the the local *
# * gateway as the destination *
# ****************************************************
# Read local iptables upnp redirects
iptables -L MINIUPNPD > tmp.txt
# Read local Gateway IP
localip=$(ifconfig wlan0 | grep "inet addr" | cut -d : -f 2 | cut -d " " -f 1)
# Set Remote router IGD rootDesc in case of failed discovery
rootdesc="http://192.168.1.254:80/upnp/IGD.xml"
# Parse temp file
while read a b; do # Read parameters from tempfile
b=$(echo $b | cut -d: -f2) # Clean port field
upnpc -u $rootdesc -a $localip $b $b $a # Set ports on remote router to local gateway
done < <(awk 'NF == 7 { print $6, $7 }' tmp.txt) # Filter tempfile with AWK
rm tmp.txt # Remove tempfile
# end
1. iptables -L MINIUPNPD | awk - redirect the output of iptables command into awk
2. NR > 2 - this is equivalent to your sed of removing the first 2 lines, mine just ignores them. (PS should you still only be wanting to look at lines with 7 arguments,
you can simply add - && NF == 7 before curly brace)
3. sub(/.*:/,"",$7) - remove everything up until the full colon from the last field (eg. dpt:19955 becomes 19955)
4. cmd = "upnpc -r -a "$5" "$7" "$6 - this is setting the variable cmd to a string representation of what you wish to execute (using your first line of input from
iptables in post #1 it would be - cmd = "upnpc -r -a 192.168.3.124 19955 tcp" )
AH! i understand! AWK is performing all the operations within the ' ' delimiters. so your script is a lot less processor use since it only calls 3 "programs" AWK, IPTABLES and UPNPC whereas mine performs alot more operations!
Only problem now is working out if i can use incron or inotify to monitor the changes to the MINIUPNPD chain and if it notices a change, run the upnpforwarder script! only thing i can think so far, and i have only just started thinkling about it, would be altering MINIUPNPD slightly to "touch" a file when it adds rules to the MNINIUPNPD chain. incron or inotify can then look for this "touch"ed file.
Sorry ... but I do not know much about iptables and nothing about MINIUPNPD. It may pay to raise another question as the gist of this one has been answered.
An alternate technique would be to alter awk's field separator to account for both spaces and colons, then you can output the field you want directly and not have to worry about splitting it later.
In case you need it broken down, -F "[[:blank:]:]+" sets the field separator to a regex that matches to "a string of one or more blank spaces and/or colons". [:blank:] is a character class that matches both space and tab, but not newline.
This should break the colon-ated part into two separate fields. Also, my personal preference is to use NR > 2 to simply skip the first two lines, instead of testing the number of fields on every line. But if you do decide to continue using NF instead, don't forget that NF == 8 now.
How about using the awk command to directly filter the output of iptables instead, so that the temp file only contains the fields you want?
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.