Re: Wrapper script for ipset listing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 07.01.2013 08:59, Jozsef Kadlecsik wrote:
On Sun, 6 Jan 2013, Jan Engelhardt wrote:

On Sunday 2013-01-06 04:50, Born Without wrote:
As I was missing those features in the ipset set listing capabilities:

- show sum of set members
- suppress listing of headers
- choose a delimiter character for separating member entries

I wrote a little wrapper script (for the bash shell) to support them.
For those who like, you'll find it attached.

There's libipset, with which this task should be achievable to the
maximum customizable degree without involving ugly text parsing with sh.

good you mention libipset, because not even the man page does, nor does any
documentation or similar exist.

I have taken Joszef into Cc..

[...]


In order to parse the output produced by ipset, one should take into
account the followings:

- New header elements may appear but the header part is always
   started by "Name:" and ended by "Members:".
- New value parameters may appear but those are appended to the existing
   ones.

If those "rules" are taken into account, then shell/perl/etc scripts can
safely parse the output.


Thank you Joszef for that information.
I've taken it into account and adapted the script.
Also added:
-a parameter to act just like 'ipset list', but with whitespace as default delim.
comments and examples.

Best regards
#!/bin/bash

# -----------------------------------------------------------------
# ipset set listing wrapper script
# -----------------------------------------------------------------
# Examples:
# $0                 - no args, just list set names
# $0 -c              - show all set names and their member sum
# $0 -t              - show all sets, but headers only
# $0 -c -m setA setB - show members and sum of setA & setB
# $0 -a -c -d :      - show all sets members, sum and use `:' as entry delimiter
# $0 -c -m -d $'\n' setA - show members and sum of setA, delim with newline
# -----------------------------------------------------------------

# -----------------------------------------------------------------
# Modify here
# -----------------------------------------------------------------
# path to ipset
ipset="/sbin/ipset"

# default delimiter character
delim=" "

# default read timeout
TMOUT=30
# -----------------------------------------------------------------

set -f
shopt -s extglob

show_all=0 show_count=0 show_members=0 headers_only=0 names_only=0 in_header=0 i=0

[[ -x $ipset ]] || {
	printf "ipset binary \`%s' does not exist, or is not executable" "$ipset"
	exit 1
}
while (($#)); do # parse cmd-line options
	case "$1" in
		-h) printf "ipset set listing wrapper script\n"
		   	printf "%s [-{a|c|h|m|n|r|s|t}] [...] [-d char] [set-name] [...]\n" "${0//*\//}"
			exit 0
		;;
		-a) show_all=1
			shift
		;;
		-c) show_count=1
			shift
		;;
		-m) show_members=1
			shift
		;;
		-n) names_only=1
			shift
		;;
		-t) headers_only=1
			arr_par[i++]="$1"
			shift
		;;
		-s|-r) arr_par[i++]="$1"
			shift
		;;
		-d) if [[ -z $2 ]]; then
				printf "delim character is missing\n" >&2
				exit 2
			else
				if ((${#2} > 1)); then
					printf "only one character is allowed as delim\n" >&2
					exit 2
				fi
				delim="$2"
				shift 2
			fi
		;;
		-o) if [[ $2 != plain ]]; then
				printf "only plain output is supported\n" >&2
				exit 2
			else
				shift 2
			fi
		;;
		-\!|-f) printf "unsupported option: \`$1'\n" >&2
				exit 2
		;;
		*) break
	esac
done

# option logic
if ((names_only && headers_only)); then
	printf "options -n and -t are mutually exclusive\n" >&2
	exit 2
elif ((headers_only)); then
	if ((show_count || show_members || show_all)); then
		printf "options -t and -a|-c|-m are mutually exclusive\n" >&2
		exit 2
	fi
elif ((names_only)); then
	if ((show_count || show_members || show_all)); then
		printf "options -n and -a|-c|-m are mutually exclusive\n" >&2
		exit 2
	fi
	"$ipset" l -n
	exit $?
fi

# sets to work on (no arg means all sets)
i=0
if [[ $1 ]]; then
	arr_opts=("$@")
else
	while IFS=$'\n' read -r; do
		arr_opts[i++]="$REPLY"
	done < <("$ipset" l -n)
	i=0
fi

# read sets
for x in "${!arr_opts[@]}"; do
	while read -r; do
		case "$REPLY" in
			"") : ;;
			Name:*) # header opened
				if ((in_header)); then
					printf "unexpected entry: \`%s' - header not closed?\n" "$REPLY" >&2
					exit 1
				fi
				i=0 in_header=1
				printf "\n%s\n" "$REPLY"
			;;
			@(Type|Header|Size in memory|References):*) # header entry
				if ((headers_only || show_all)); then
					printf "%s\n" "$REPLY"
				fi
			;;
			Revision:*) # header entry (closes header on -t)
				if ((headers_only)); then
					in_header=0
					printf "%s\n" "$REPLY"
				elif ((show_all)); then
					printf "%s\n" "$REPLY"
				fi
			;;
			Members:*) # header entry (closes header if not -t)
				in_header=0
				if ((show_all)); then
					printf "%s\n" "$REPLY"
				fi
			;;
			*) # member entry
			   	if ((in_header)); then
					printf "unexpected entry: \`%s'\n" "$REPLY" >&2
					exit 1
				fi
				if ((show_members || show_all)); then
					printf "%s$delim" "$REPLY"
				fi
				let i+=1
		esac
	done < <("$ipset" l "${arr_opts[x]}" "${arr_par[@]}")
	if ((show_members || show_all)) && [[ $delim != $'\n' ]]; then
		printf "\n"
	fi
	if ((show_count)); then
		printf "Member count: %d\n" $i
	fi
done

[Index of Archives]     [Linux Netfilter Development]     [Linux Kernel Networking Development]     [Netem]     [Berkeley Packet Filter]     [Linux Kernel Development]     [Advanced Routing & Traffice Control]     [Bugtraq]

  Powered by Linux