@@ -111,9 +111,20 @@ if [[ -z "$1" || -z "$2" || -z "$3" || -z "$4" || -z "$5" ]]; then
111
111
exit 1
112
112
fi
113
113
114
- # Ensure the reported IP list file exists
114
+ # Ensure the directory for the reported IP list exists
115
+ REPORTED_IP_DIR=$( dirname " ${REPORTED_IP_LIST_FILE} " )
116
+ if [[ ! -d " ${REPORTED_IP_DIR} " ]]; then
117
+ mkdir -p " ${REPORTED_IP_DIR} " || { log_message " FATAL: Could not create directory ${REPORTED_IP_DIR} " ; exit 1; }
118
+ fi
119
+
120
+ # Ensure the reported IP list file exists and is writable
115
121
if [[ ! -f " ${REPORTED_IP_LIST_FILE} " ]]; then
116
- touch " ${REPORTED_IP_LIST_FILE} "
122
+ touch " ${REPORTED_IP_LIST_FILE} " || { log_message " FATAL: Could not create file ${REPORTED_IP_LIST_FILE} " ; exit 1; }
123
+ fi
124
+
125
+ if [[ ! -w " ${REPORTED_IP_LIST_FILE} " ]]; then
126
+ log_message " FATAL: File ${REPORTED_IP_LIST_FILE} is not writable."
127
+ exit 1
117
128
fi
118
129
119
130
# Check runtime dependencies
@@ -127,73 +138,69 @@ if ! command -v jq &>/dev/null; then
127
138
exit 1
128
139
fi
129
140
130
- # Function to check if the IP is listed on AbuseIPDB
141
+ # Check if the IP is listed on AbuseIPDB
131
142
check_ip_in_abuseipdb () {
132
- local response
133
- local http_status
134
- local body
135
- local exit_code
136
- local total_reports
137
- local error_detail
143
+ local response http_status body exit_code total_reports error_detail
144
+ local delimiter=" HTTP_STATUS:"
138
145
139
146
# Perform the API call and capture both response and HTTP status
140
- response=$( curl -s -w " HTTPSTATUS: %{http_code}" -G " https://api.abuseipdb.com/api/v2/check" \
147
+ response=$( curl -s -w " ${delimiter} %{http_code}" -G " https://api.abuseipdb.com/api/v2/check" \
141
148
--data-urlencode " ipAddress=${IP} " \
142
149
-H " Key: ${APIKEY} " \
143
150
-H " Accept: application/json" 2>&1 )
144
151
145
- exit_code=$?
146
-
147
- # Extract the HTTP status code
148
- http_status=$( echo " ${response} " | tr -d ' \n' | sed -e ' s/.*HTTPSTATUS://' )
149
-
150
- # Extract the body
151
- body=$( echo " ${response} " | sed -e ' s/HTTPSTATUS\:.*//g' )
152
-
153
- # Check if curl encountered a network or other fatal error
154
- if [[ $exit_code -ne 0 ]]; then
155
- log_message " Aborting due to curl failure when checking IP. Exit code: ${exit_code} , Response: ${response} "
152
+ if [[ $? -ne 0 ]]; then
153
+ log_message " ERROR CHECK: API failure. Response: ${response} "
156
154
exit 1
157
155
fi
158
156
157
+ # Separate the HTTP status code from the response body
158
+ http_status=$( echo " ${response} " | tr -d ' \n' | sed -e " s/.*${delimiter} //" )
159
+ body=$( echo " ${response} " | sed -e " s/${delimiter} [0-9]*//" )
160
+
159
161
# Check if the response body is empty
160
162
if [[ -z " ${body} " ]]; then
161
- log_message " API response was empty when checking IP ."
163
+ log_message " ERROR CHECK: API response empty."
162
164
exit 1
163
165
fi
164
166
165
- # Validate the JSON response
167
+ # Validate that the response is valid JSON
166
168
if ! echo " ${body} " | jq . > /dev/null 2>&1 ; then
167
- log_message " API response was malformed when checking IP . Response: ${body} "
169
+ log_message " ERROR CHECK: API response malformed. Response: ${body} "
168
170
exit 1
169
171
fi
170
172
171
173
# Handle different HTTP status codes
172
- if [[ " ${http_status} " -ge 200 && " ${http_status} " -lt 300 ]]; then
173
- # Successful HTTP response; now check for API-level errors
174
- if echo " ${body} " | jq -e ' .errors' > /dev/null 2>&1 ; then
175
- error_detail=$( echo " ${body} " | jq -r ' .errors[].detail' )
176
- log_message " API returned errors when checking IP. Detail: ${error_detail} "
174
+ if [[ " ${http_status} " =~ ^[0-9]+$ ]]; then
175
+ if [[ " ${http_status} " -ge 200 && " ${http_status} " -lt 300 ]]; then
176
+ # Successful HTTP response; check for API-level errors
177
+ if echo " ${body} " | jq -e ' .errors | length > 0' > /dev/null 2>&1 ; then
178
+ error_detail=$( echo " ${body} " | jq -r ' .errors[].detail' )
179
+ log_message " ERROR CHECK: API returned errors. Detail: ${error_detail} "
180
+ exit 1
181
+ fi
182
+ else
183
+ # Non-successful HTTP status
184
+ log_message " ERROR CHECK: API returned ${http_status} . Response: ${body} "
177
185
exit 1
178
186
fi
179
187
else
180
- # Non-successful HTTP status codes
181
- log_message " API returned HTTP status ${http_status} when checking IP. Response: ${body} "
188
+ log_message " ERROR CHECK: HTTP status '${http_status} ' is not numeric."
182
189
exit 1
183
190
fi
184
191
185
192
# Extract totalReports
186
193
total_reports=$( echo " ${body} " | jq ' .data.totalReports' )
187
194
188
- # Check the IP listed on AbuseIPDB
195
+ # Finally, check the IP listed on AbuseIPDB
189
196
if [[ " ${total_reports} " -gt 0 ]]; then
190
197
return 0 # IP is reported
191
198
else
192
199
return 1 # IP is not reported
193
200
fi
194
201
}
195
202
196
- # Function to report an IP to AbuseIPDB
203
+ # Report to AbuseIpDB
197
204
report_ip_to_abuseipdb () {
198
205
local response
199
206
response=$( curl --fail -s ' https://api.abuseipdb.com/api/v2/report' \
@@ -205,23 +212,23 @@ report_ip_to_abuseipdb() {
205
212
206
213
# API call fail
207
214
if [[ $? -ne 0 ]]; then
208
- log_message " Aborting due to API failure when reporting IP . Response: ${response} "
215
+ log_message " ERROR REPORT: API failure. Response: ${response} "
209
216
exit 1
210
217
else
211
- log_message " Reported IP ${IP} to AbuseIPDB. Local list updated."
218
+ log_message " SUCCESS REPORT: Reported IP ${IP} to AbuseIPDB. Local list updated."
212
219
fi
213
220
}
214
221
215
- # Should Ban IP
216
- if grep -q -E " ^IP=${IP} L=[0-9\-]+" " ${REPORTED_IP_LIST_FILE} " ; then
217
- # IP is already reported , check if it's still listed on AbuseIPDB
222
+ # Check if IP is already reported and still listed on AbuseIPDB
223
+ if grep -q -E " ^IP=${IP} [[:space:]]+ L=[0-9\-]+" " ${REPORTED_IP_LIST_FILE} " ; then
224
+ # IP found locally , check if it's still listed on AbuseIPDB
218
225
if check_ip_in_abuseipdb; then
219
226
# IP is still listed on AbuseIPDB, no need to report again
220
- log_message " IP ${IP} has already been reported and remains on AbuseIPDB. No duplicate report made."
227
+ log_message " INFO: IP ${IP} has already been reported and remains on AbuseIPDB. No duplicate report made."
221
228
shouldBanIP=0
222
229
else
223
- # IP is already reported before but not listed on AbuseIPDB, report it again
224
- log_message " IP ${IP} has already been reported but is no longer listed on AbuseIPDB. Reporting it again."
230
+ # IP is reported before but not listed on AbuseIPDB, report it again
231
+ log_message " INFO: IP ${IP} has already been reported but is no longer listed on AbuseIPDB. Reporting it again."
225
232
shouldBanIP=1
226
233
is_found_local=1
227
234
fi
@@ -230,20 +237,15 @@ else
230
237
shouldBanIP=1
231
238
fi
232
239
233
- # Report to AbuseIPDB
240
+ # Report to AbuseIpdb
234
241
if [[ " ${shouldBanIP} " -eq 1 ]]; then
235
242
# Add the new ban entry to local list kindly
236
243
if [[ " ${is_found_local} " -eq 0 ]]; then
237
- # Open with read/write access
238
- exec 200<> " ${REPORTED_IP_LIST_FILE} "
239
- # Lock
240
- flock -x 200
241
- # Write
242
- echo " IP=${IP} L=${BANTIME} " >> " ${REPORTED_IP_LIST_FILE} "
243
- # Release the lock (Maybe redundant)
244
- flock -u 200
245
- # Close the file descriptor
246
- exec 200>& -
244
+ exec 200<> " ${REPORTED_IP_LIST_FILE} " # Open with read/write access
245
+ flock -x 200 # Lock
246
+ echo " IP=${IP} L=${BANTIME} " >> " ${REPORTED_IP_LIST_FILE} " # Write
247
+ flock -u 200 # Release the lock
248
+ exec 200>& - # Close the file descriptor
247
249
fi
248
250
249
251
# Report IP
0 commit comments