Luci openWRT UCI firewall rule update without position number - bash

Hey all I have been trying find some code that would allow me to update my firewall rule via the UCI.
The way I am currently adding the new rule is like this:
uci add firewall rule
uci set firewall.#rule[21].name='B Macbook Air'
uci set firewall.#rule[21].src='lan'
uci set firewall.#rule[21].family='ipv4'
uci set firewall.#rule[21].src_ip='192.168.1.227'
uci set firewall.#rule[21].src_mac='00:00:00:00:00:00'
uci set firewall.#rule[21].dest='wan'
uci set firewall.#rule[21].proto='all'
uci set firewall.#rule[21].target='REJECT'
uci set firewall.#rule[21].enabled='1'
uci commit firewall
This produces the correct rule inside luci (branch (git-22.347.45520-d30ab74)):
The way I update one of the rules' enabled or disable is this:
uci set firewall.#rule[21].name="B Macbook Air"
uci set firewall.#rule[21].enabled="1"
uci commit firewall
Which works as expected but I am wondering if there's a way too just call the firewall rules name instead of needing to know the position (ie: [21])?
Like this:
uci set firewall.#rule.name="B Macbook Air"
uci set firewall.#rule.enabled="1"
uci commit firewall
But of course the above does not work. Gives an error of
root#turris:~# uci set firewall.#rule.name="B Macbook Air"
uci: Invalid argument
Is this possible to do?

You can write a loop to check each rule's .name.
The following example supposes the index numbers start from 0 and are consecutive.
(Not sure if bash is installed by default. The example code is in sh.)
#!/bin/sh
name='Support-UDP-Traceroute'
option=enabled
value=1
i=0
while true; do
rname=$( uci get "firewall.#rule[$i].name" 2> /dev/null )
if [ $? != 0 ]; then
# no more rules
break
fi
if [ "$rname" = "$name" ]; then
echo "found: $name: [$i]"
# uci set firewall.#rule[$i].$option="$value"
# uci commit firewall
break
fi
let i++
done
Make it a function if you need to do this often. And you need to update it a bit if the index numbers are not consecutive.
Another solution is to use uci show firewall:
i=$( uci show firewall | grep/sed/awk/... )
uci set firewall.#rule[$i].the_option="the_value"
uci commit firewall
This way you don't care if the index numbers are consecutive or not.

Related

How to get the output of execute shell script in lua api

I am newbie in luci and lua api. Now I have problem about remove firewall rule from luci webgui in opnewrt. I know delete the rule is using the uci command : uci delete firewall.#rule[index]
But I don't know the index exectly. So I use blow shell script name index.sh to find the index by key word.
uci show firewall | grep $1 | grep -oE '\[.*?\]' | sed 's/[][]//g' | head -n 1
Here $1 is the mac address.
My process is get the mac address from luci web and remove the firewall rule of block the
network access from the mac address I set before. To recover the network access of the mac address.
But I use the lua api of luci.sys.exec and luci.util.exec to get the output of firewall rule index that are all wrong.
My example code:
1.Get the mac address from luci
local del_mac = protocol.urldecode(luci.http.formvalue("deleteMac"))
2.Execute the the shell script to get the index
local ruleindex = ut.trim(tostring(luci.sys.exec("index.sh '" .. del_mac .."'"))
local uci_delete_rule = "uci delete firewall.#rule['" .. ruleindex .. "]'"
luci.sys.exec(uci_delete_rule)
or
local index = "index.sh %s" %{list_del_mac}
local rule_index = ut.trim(tostring(luci.util.exe(index)))
local uci_delete_rule = "uci delete firewall.#rule['" .. rule_index .. "]'"
luci.sys.exec(uci_delete_rule)
3.Reload the firewall rule
luci.sys.exec("uci commit firewall")
luci.sys.exec("fw3 reload")
Can anyone help me to reslove the problem?
Thank you for your help
This doesn't look right to me: "index.sh %s" %{list_del_mac} Unless it's short for string.format in luci, that's not proper Lua. Concatenate your command string, or actually use string.format
"index.sh " ..list_del_mac
or
string.format( "index.sh %s", list_del_mac )
also, to get the return value after execution, you need to send it to a variable
return_value = luci.sys.exec(uci_delete_rule)
print( return_value )

Changing MacOS Location based on SSID - check current location before changing

In this thread I received some assistance with getting this script to work correctly. The script essentially sets my network location according to the SSID I'm connected to. This is now working, however, it generates a lot of nuisance notifications.
Every time my laptop joins a wifi network, the script runs, sets the network location, and gives me a notification. Since power nap periodically joins the wifi to check for emails/updates and what have you, after a long weekend I'll get dozens of identical notifications.
How can I modify the script so that it only send a notification if the network location is changed to something different, not just when the script runs? Can I somehow check the existing network location and only change it/trigger a notification if the "new" location is different to the "existing" location?
Again, I'm extremely new to scripting on mac and GitHub in general; my previous experience is all on Windows and largely self taught.
Script:
#!/bin/bash
# automatically change configuration of Mac OS X based on location
# redirect all IO to a logfile
mkdir -p /usr/local/var/log
exec &>/usr/local/var/log/locationchanger.log
# get a little breather before we get data for things to settle down
sleep 2
# get SSID
SSID=$(/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -I | sed -n 's/^ *SSID: //p')
echo $(date) "New SSID found: $SSID"
# LOCATIONS
LOCATION=
Location_Automatic="Automatic"
Location_Office="Office"
Location_Site="Site"
# SSIDS
SSID_Office="My Office SSID"
SSID_Site="My Mobile SSID"
# SSID -> LOCATION mapping
case $SSID in
"$SSID_Office") LOCATION="$Location_Office";;
"$SSID_Site" ) LOCATION="$Location_Site";;
esac
REASON="SSID changed to $SSID"
# Location_Automatic
if [ -z "$LOCATION" ]; then
LOCATION="$Location_Automatic"
REASON="Automatic Fallback"
fi
# change network location
scselect "$LOCATION"
case $LOCATION in
"$Location_Automatic" )
osascript -e 'display notification "Network Location Changed to Automatic" with title "Network Location Changed"'
;;
"$Location_Office" )
osascript -e 'display notification "Network Location Changed to Office" with title "Network Location Changed"'
;;
"$Location_Site" )
osascript -e 'display notification "Network Location Changed to Site" with title "Network Location Changed"'
;;
esac
echo "--> Location Changer: $LOCATION - $REASON"
exit 0
This thread explains how to get the current network location.
I added the following code to get the current network location before making any changes:
CurrLoc=$(scselect | awk '{if ($1=="*") print $3}' | sed 's/[()]//g')
And then a simple if statement to exit the script early if the evaluated "new" network location matched the existing one:
if [ "$CurrLoc" = "$LOCATION" ]
then
exit 0
fi
# existing code to change network location and show notifications

How to set system variables in start-up scripts

I'm controlling 8 servos using the PWM outputs on the BeagleBone. On start-up the names of the PWMs are dynamically assigned so they vary from boot to boot, so to know which pin matches which PWM I've written this script:
#!/bin/sh
# match BeagleBone PWMCHIP{n} with available pwm controllers
for i in $(/bin/ls /sys/class/pwm); do
link=$(/bin/readlink /sys/class/pwm/$i)
case "$link" in
*48300100*) BBPWM0=$i;;
*48300200*) BBPWM1=$i;;
*48302200*) BBPWM2=$i;;
*48304100*) BBPWM3=$i;;
*48304200*) BBPWM4=$i;;
esac
done
export BBPWM0
export BBPWM1
export BBPWM2
export BBPWM3
export BBPWM4
echo "PWM0 = $BBPWM0" > /home/ormund/servo.log
/home/ormund/servo-server
The system works when I start it from the command line, the servo-server listens on a network port and moves the servos correctly in response to remote commands, but if I start this from systemd at boot, it fails, the BBPWM0 is a null string and the server cant start. What am I doing wrong?

Windows routes - add many lines to routes table at once

I have to add many lines (rules) to the routes table in Windows.
The regular way is to add it with:
route add 10.0.0.0 mask 240.0.0.0 192.168.0.1
However, if I want to add many lines at once (belive me I have a good reason to do it) - how can I do it quickly (running "route add" is slow)?
I tried running it in some threads and it still slow.
Option 1:
You can use this MS tool: netsh
Netsh is a command-line scripting utility that allows you to, either
locally or remotely, display or modify the network configuration of a
computer that is currently running.
Build a file with all the lines you want to add, like this:
[For more information on "add route" command and its parameters, see here].
# ----------------------------------
# IPv4 Configuration
# ----------------------------------
pushd interface ipv4
add route prefix=10.0.0.0/4 interface="Ethernet" nexthop=192.168.0.1 metric=1 publish=Yes
add route prefix=240.0.0.0/4 interface="Ethernet" nexthop=192.168.0.1 metric=1 publish=Yes
[and so on...]
popd
# End of IPv4 configuration
Save it in a *.dat file, and run this command:
netsh exec file.dat
Option 2:
[As Harry Johnston commented]: You can use CreateIpForwardEntry function to add route (example code in the link).
The CreateIpForwardEntry function creates a route in the local
computer's IPv4 routing table.

Bash case not properly evaluating value

The Problem
I have a script that has a case statement which I'm expecting to execute based on the value of a variable. The case statement appears to either ignore the value or not properly evaluate it instead dropping to the default.
The Scenario
I pull a specific character out of our server hostnames which indicates where in our environment the server resides. We have six different locations:
Management(m): servers that are part of the infrastructure such as monitoring, email, ticketing, etc
Development(d): servers that are for developing code and application functionality
Test(t): servers that are used for initial testing of the code and application functionality
Implementation(i): servers that the code is pushed to for pre-production evaluation
Production(p): self-explanatory
Services(s): servers that the customer needs to integrate that provide functionality across their project. These are separate from the Management servers in that these are customer servers while Management servers are owned and operated by us.
After pulling the character from the hostname I pass it to a case block. I expect the case block to evaluate the character and add a couple lines of text to our rsyslog.conf file. What is happening instead is that the case block returns the default which does nothing but tell the person building the server to manually configure the entry due to an unrecognized character.
I've tested this manually against a server I recently built and verified that the character I am pulling from the hostname (an 's') is expected and accounted for in the case block.
The Code
# Determine which environment our server resides in
host=$(hostname -s)
env=${host:(-8):1}
OLDFILE=/etc/rsyslog.conf
NEWFILE=/etc/rsyslog.conf.new
# This is the configuration we need on every server regardless of environment
read -d '' common <<- EOF
...
TEXT WHICH IS ADDED TO ALL CONFIG FILES REGARDLESS OF FURTHER CODE EXECUTION
SNIPPED
....
EOF
# If a server is in the Management, Dev or Test environments send logs to lg01
read -d '' lg01conf <<- EOF
# Relay messages to lg01
*.notice ##xxx.xxx.xxx.100
#### END FORWARDING RULE ####
EOF
# If a server is in the Imp, Prod or is a non-affiliated Services zone server send logs to lg02
read -d '' lg02conf <<- EOF
# Relay messages to lg02
*.notice ##xxx.xxx.xxx.101
#### END FORWARDING RULE ####
EOF
# The general rsyslog configuration remains the same; pull it out and write it to a new file
head -n 63 $OLDFILE > $NEWFILE
# Add the common language to our config file
echo "$common" >> $NEWFILE
# Depending on which environment ($env) our server is in, add the appropriate
# remote log server to the configuration with the $common settings.
case $env in
m) echo "$lg01conf" >> $NEWFILE;;
d) echo "$lg01conf" >> $NEWFILE;;
t) echo "$lg01conf" >> $NEWFILE;;
i) echo "$lg02conf" >> $NEWFILE;;
p) echo "$lg02conf" >> $NEWFILE;;
s) echo "$lg02conf" >> $NEWFILE;;
*) echo "Unknown environment; Manually configure"
esac
# Keep a dated backup of the original rsyslog.conf file
cp $OLDFILE $OLDFILE.$(date +%Y%m%d)
# Replace the original rsyslog.conf file with the new version
mv $NEWFILE $OLDFILE
An Aside
I've already determined that I can combine the different groups of code from the case block onto single lines (a total of two) using the | operator. I've listed it in the manner above since this is how it is coded while I'm having issues with it.
I can't see what's wrong with your code. Maybe add another ;; to the default clause. To find the problem add a set -vx as a first line. Will show you lots of debug information.

Resources