Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GeoIP banning from ipdeny list #37

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 43 additions & 42 deletions api/ipsets/read
Expand Up @@ -37,50 +37,51 @@ def get_config():


def get_categories():
path = "/usr/share/nethserver-blacklist/ipsets"
paths = ["/usr/share/nethserver-blacklist/ipsets","/usr/share/nethserver-blacklist/geoips"]
categories = []

if os.path.exists(path):
for file_name in os.listdir(path):
if file_name.endswith(".ipset") or file_name.endswith(".netset"):
full_path = path + "/" + file_name
category = {
'confidence': 0 # // default value
}

with open(full_path) as f:
lines = f.readlines()

for line in lines:
# parse only the header
if not re.match(r"^#", line):
break

# skip empty lines
if re.match(r"^\s*$", line):
continue

maintainer = re.search(r"Maintainer\s+:\s+(\w+)", line)
if maintainer:
category['maintainer'] = maintainer.group(1)
continue

category_type = re.search(r"Category\s+:\s+(\w+)", line)
if category_type:
category['type'] = category_type.group(1)
continue

confidence = re.search(r"Confidence\s+:\s+(\w+)", line)
if confidence:
category['confidence'] = int(confidence.group(1))
continue

f.closed
category_id = re.search(r"(.+)\..+", file_name).group(1)
category['id'] = category_id
name = category_id.replace("_", " ").capitalize()
category['name'] = name
categories.append(category)
for path in paths:
if os.path.exists(path):
for file_name in os.listdir(path):
if file_name.endswith(".ipset") or file_name.endswith(".netset"):
full_path = path + "/" + file_name
category = {
'confidence': 0 # // default value
}

with open(full_path) as f:
lines = f.readlines()

for line in lines:
# parse only the header
if not re.match(r"^#", line):
break

# skip empty lines
if re.match(r"^\s*$", line):
continue

maintainer = re.search(r"Maintainer\s+:\s+(\w+)", line)
if maintainer:
category['maintainer'] = maintainer.group(1)
continue

category_type = re.search(r"Category\s+:\s+(\w+)", line)
if category_type:
category['type'] = category_type.group(1)
continue

confidence = re.search(r"Confidence\s+:\s+(\w+)", line)
if confidence:
category['confidence'] = int(confidence.group(1))
continue

f.closed
category_id = re.search(r"(.+)\..+", file_name).group(1)
category['id'] = category_id
name = category_id.replace("_", " ").capitalize()
category['name'] = name
categories.append(category)

return categories

Expand Down
3 changes: 2 additions & 1 deletion api/ipsets/update
Expand Up @@ -26,14 +26,15 @@
data=$(cat /dev/stdin)

status=$(echo $data | jq -r '.status')
GeoipStatus=$(echo $data | jq -r '.GeoipStatus')
url=$(echo $data | jq -r '.Url')
whitelist=$(echo $data | jq -r '.Whitelist | join(",")')
categories=$(echo $data | jq -r '.Categories | join(",")')

current_url=$(/sbin/e-smith/config getprop blacklist Url)

if [ "$status" = "enabled" ]; then
/sbin/e-smith/config setprop blacklist status "$status" Url "$url" Whitelist "$whitelist" Categories "$categories"
/sbin/e-smith/config setprop blacklist status "$status" GeoipStatus "$GeoipStatus" Url "$url" Whitelist "$whitelist" Categories "$categories"

if [ $? -gt 0 ]; then
invalid_error
Expand Down
14 changes: 12 additions & 2 deletions api/ipsets/validate
Expand Up @@ -44,6 +44,7 @@ input_json = simplejson.loads(line)
invalid_attributes = []

status_p = 'status'
GeoipStatus_p = 'GeoipStatus'
url_p = 'Url'
whitelist_p = 'Whitelist'
categories_p = 'Categories'
Expand All @@ -63,12 +64,21 @@ else:
if status not in ['enabled', 'disabled']:
invalid_attributes.append(invalid_attribute(status_p, "invalid"))


# perform all other validations only if status == 'enabled'
if status == 'enabled':
# GeoipStatus
if (GeoipStatus_p not in input_json) or (not input_json[GeoipStatus_p]):
invalid_attributes.append(invalid_attribute(GeoipStatus_p, "empty"))
else:
GeoipStatus = input_json[GeoipStatus_p]

if GeoipStatus not in ['enabled', 'disabled']:
invalid_attributes.append(invalid_attribute(GeoipStatus_p, "invalid"))
# url
if (url_p not in input_json) or (not input_json[url_p]):
if (url_p not in input_json):
invalid_attributes.append(invalid_attribute(url_p, "empty"))
else:
elif (input_json[url_p]):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change makes me think that URL is not mandatory anymore, but inside download script it looks like it is still mandatory. Am i missing something? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a python guru like you @andre8244, I tested some ways.

Now the url is not a mandatory, if the URL exists then we download (see https://github.com/NethServer/nethserver-blacklist/pull/37/files#diff-af724284fab7ff3dbe0e6c5d083dd81c6c30bddb4a030f75431ef294796b3404R38) same in the cron job ( see https://github.com/NethServer/nethserver-blacklist/pull/37/files#diff-78e4181675f2cbc15bc508d9a79c151096229bc2a3a4cb4bff0a29957c88b9e4R4)

Another way could be to have a third checkbox in the UI to enable git blacklist and a new property in the esmith key

we still check if the url is a valid url and if it is a git repository

url = input_json[url_p]

# check syntax
Expand Down
@@ -0,0 +1 @@
disabled
30 changes: 23 additions & 7 deletions root/etc/e-smith/events/actions/nethserver-blacklist-conf
Expand Up @@ -27,15 +27,31 @@ event=$1 # name of the event (not used)
type=$2 # blacklist type (ipsets or dnss)

if [[ "$type" == "ipsets" ]]; then
conf="blacklist"
status=$(/sbin/e-smith/config getprop blacklist status)
ipsetUrl=$(/sbin/e-smith/config getprop blacklist Url)
GeoipStatus=$(/sbin/e-smith/config getprop blacklist GeoipStatus)

if [[ "$status" != "enabled" ]]; then
exit 0
fi

if [[ "$ipsetUrl" != "" ]]; then
/usr/share/nethserver-blacklist/download ipsets
fi
Comment on lines +38 to +40
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a real condition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the comment below, the URL is not more a mandatory, we use it like a new checkbox in the UI, if the URL is a valid git repository and if the URL exists then we download the list and use this list to the cronjob

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's a good choice, I need to test it.
I will do it probably tomorrow :)

if [[ "$GeoipStatus" == "enabled" ]]; then
/usr/share/nethserver-blacklist/download geoip
else
/usr/bin/rm -f /usr/share/nethserver-blacklist/geoips/*
fi

elif [[ "$type" == "dnss" ]]; then
conf="ftl"
status=$(/sbin/e-smith/config getprop ftl status)

if [[ "$status" == "enabled" ]]; then
exec /usr/share/nethserver-blacklist/download dnss
fi

else
echo "Invalid blacklist type: $type"
exit 1
fi

status=$(/sbin/e-smith/config getprop $conf status)
if [[ "$status" == "enabled" ]]; then
exec /usr/share/nethserver-blacklist/download $type
fi
@@ -1,6 +1,9 @@
{
my $ip_status = $blacklist{'status'} || 'disabled';
if ($ip_status eq 'enabled') {
my $GeoipStatus = $blacklist{'GeoipStatus'} || 'disabled';
my $ipsetUrl = $blacklist{'Url'} || '';

if (($ip_status eq 'enabled') && ($ipsetUrl ne '')) {
$OUT .= '*/20 * * * * root sleep $(( ( RANDOM \% 60 ) )); /usr/share/nethserver-blacklist/download ipsets'
} else {
$OUT .= "# Blacklists (ip) are disabled"
Expand All @@ -14,4 +17,12 @@
} else {
$OUT .= "# Blacklists (dns) are disabled"
}

$OUT .= "\n";

if (($ip_status eq 'enabled') && ($GeoipStatus eq 'enabled')) {
$OUT .= '* 3 * * * root sleep $(( ( RANDOM \% 7200 ) )); /usr/share/nethserver-blacklist/download geoip'
} else {
$OUT .= "# Blacklists (geoip) are disabled"
}
}
4 changes: 4 additions & 0 deletions root/usr/share/nethserver-blacklist/download
Expand Up @@ -33,6 +33,10 @@ case $TYPE in
dnss)
PROP=ftl
;;

geoip)
exec /usr/share/nethserver-blacklist/geoip
;;
esac

URL=$(/sbin/e-smith/config getprop $PROP Url)
Expand Down
47 changes: 47 additions & 0 deletions root/usr/share/nethserver-blacklist/geoip
@@ -0,0 +1,47 @@
#!/bin/bash
#
# Copyright (C) 2021 Nethesis S.r.l.
# http://www.nethesis.it - nethserver@nethesis.it
#
# This script is part of NethServer.
#
# NethServer is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License,
# or any later version.
#
# NethServer is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with NethServer. If not, see COPYING.
#

dir=`/usr/bin/mktemp -d`

/usr/bin/cd $dir
/usr/bin/wget https://www.ipdeny.com/ipblocks/data/countries/all-zones.tar.gz >/dev/null 2>&1
tar -xf all-zones.tar.gz
for j in *.zone
do
echo "#
# ipv4 hash:ip ipset
# Category : geoip_blocking
# Source File Date : $(/usr/bin/date)
# Maintainer : NethServer
# List source URL : https://www.ipdeny.com/ipblocks/data/countries/all-zones.tar.gz
# ISO Country Code : ${j%.zone}
#
$(/usr/bin/cat ${j})" > ${j}
/usr/bin/mv -- "$j" "ISO_country_code_${j%.zone}.netset"
stephdl marked this conversation as resolved.
Show resolved Hide resolved
done

# ensure ipset directory is created
/usr/bin/mkdir -p /usr/share/nethserver-blacklist/geoips
/usr/bin/rm -f /usr/share/nethserver-blacklist/geoips/*
/usr/bin/mv *.netset /usr/share/nethserver-blacklist/geoips/
/usr/bin/rm -rf $dir
/usr/share/nethserver-blacklist/load-ipsets --reload
exit $?
55 changes: 28 additions & 27 deletions root/usr/share/nethserver-blacklist/load-ipsets
Expand Up @@ -20,7 +20,7 @@
# along with NethServer. If not, see COPYING.
#

BLDIR=/usr/share/nethserver-blacklist/ipsets
BLDIR=(/usr/share/nethserver-blacklist/ipsets /usr/share/nethserver-blacklist/geoips)
STATUS=$(/sbin/e-smith/config getprop blacklist status)
MAXELEM=$(/sbin/e-smith/config getprop blacklist MaxElem)
LISTS=$(/sbin/e-smith/config getprop blacklist Categories | tr , ' ')
Expand Down Expand Up @@ -91,30 +91,31 @@ if [ -f $BLDIR/whitelist.global ]; then
cat $BLDIR/whitelist.global | sed '/^#/d; /^$/d' | sed "s/^/add bl-whitelist /" | /sbin/ipset restore
fi

for l in $LISTS; do
file=''
type=''
file_netset="$BLDIR/$l".netset
file_ipset="$BLDIR/$l".ipset
name=$(echo "bl-$l" | cut -c 1-31) # limit to 31 chars
if [ -f $file_netset ]; then
file=$file_netset
type="hash:net"
elif [ -f $file_ipset ]; then
file=$file_ipset
type="hash:ip"
else
warning "Skipping invalid blacklist '$l'"
continue
fi
debug "Creating ipset $name"
# Create ipset and load IPs
/sbin/ipset create -exist $name $type maxelem ${MAXELEM:-131072}
if [ $? -gt 0 ]; then
warning "Can't create $name ipset"
fi
cat $file | sed '/^#/d; /^$/d' | sed "s/^/add $name /" | /sbin/ipset restore
if [ $? -gt 0 ]; then
warning "Can't load $name ipset"
fi
for dir in "${BLDIR[@]}"; do
for l in $LISTS; do
file=''
type=''
file_netset="$dir/$l".netset
file_ipset="$dir/$l".ipset
name=$(echo "bl-$l" | cut -c 1-31) # limit to 31 chars
if [ -f $file_netset ]; then
file=$file_netset
type="hash:net"
elif [ -f $file_ipset ]; then
file=$file_ipset
type="hash:ip"
else
continue
fi
debug "Creating ipset $name"
# Create ipset and load IPs
/sbin/ipset create -exist $name $type maxelem ${MAXELEM:-131072}
if [ $? -gt 0 ]; then
warning "Can't create $name ipset"
fi
cat $file | sed '/^#/d; /^$/d' | sed "s/^/add $name /" | /sbin/ipset restore
if [ $? -gt 0 ]; then
warning "Can't load $name ipset"
fi
done
done
3 changes: 2 additions & 1 deletion ui/public/i18n/language.json
Expand Up @@ -84,7 +84,8 @@
},
"ip_blacklist": {
"title": "IP blacklist",
"enable_ip_blacklist": "Enable IP blacklist"
"enable_ip_blacklist": "Enable IP blacklist",
"enable_geoip_blacklist": "Enable geoip blacklist"
},
"dns_blacklist": {
"title": "DNS blacklist",
Expand Down
23 changes: 23 additions & 0 deletions ui/src/views/IpBlacklist.vue
Expand Up @@ -49,6 +49,22 @@
/>
</div>
</div>
<!-- GeoipStatus -->
<div class="form-group">
<label
class="col-sm-2 control-label"
for="blacklist-GeoipStatus"
>{{$t('ip_blacklist.enable_geoip_blacklist')}}</label>
<div class="col-sm-5">
<input
type="checkbox"
v-model="config.GeoipStatus"
id="blacklist-GeoipStatus"
class="form-control"
:disabled="!config.status"
/>
</div>
</div>
<!-- download url -->
<div :class="['form-group', {'has-error': error.url}]">
<label class="col-sm-2 control-label" for="blacklist-url">
Expand Down Expand Up @@ -311,6 +327,7 @@ export default {
},
config: {
status: false,
GeoipStatus: false,
url: "",
whitelist: [],
categories: [],
Expand Down Expand Up @@ -442,6 +459,11 @@ export default {
} else {
context.config.status = false;
}
if (props.GeoipStatus === "enabled") {
context.config.GeoipStatus = true;
} else {
context.config.GeoipStatus = false;
}
context.config.url = props.Url;
context.config.lastUrl = context.config.url;
context.config.whitelist = context.buildWhitelist(props.Whitelist);
Expand Down Expand Up @@ -561,6 +583,7 @@ export default {

var validateObj = {
status: this.config.status ? "enabled" : "disabled",
GeoipStatus: this.config.GeoipStatus ? "enabled" : "disabled",
Url: this.config.url,
Whitelist: this.getWhitelistIds(),
Categories: this.getSelectedCategoriesIds()
Expand Down