[PATCH] [white|black]list for receiver addresses

Stipe Tolj <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Organization Kannel Software Foundation (KSF)
Message-ID <[email protected]>
Hi list,

this is a very intuitive addition to the way we allow handling 
'[white|black]-list[-regex]' config directives in the 'group = core' 
context.

Unfortunately the existing logic only patterns against the 
msg->sms.sender (source address) of the message, but not against the 
receiver side.

While you may argue that this SHOULD be done by the upper application 
layer instead, some may find it useful to be added as feature add into 
the baseline svn trunk.

Please review and vote for committing.

Stipe

-- 
-------------------------------------------------------------------
Kölner Landstrasse 419
40589 DÃŒsseldorf, NRW, Germany

Kannel Foundation                 tolj.org system architecture
http://www.kannel.org/            http://www.tolj.org/

mailto:stolj_{at}_kannel.org      mailto:st_{at}_tolj.org
-------------------------------------------------------------------
gateway-white-black-list.diff (text/plain, 21.1 KB)
Index: doc/userguide/userguide.xml
===================================================================
--- doc/userguide/userguide.xml	(revision 5091)
+++ doc/userguide/userguide.xml	(working copy)
@@ -1399,19 +1399,71 @@
      <entry valign="bottom">
         Load a list of accepted senders of SMS messages. If a sender
         of an SMS message is not in this list, any message received
-        from the SMS Center is discarded. See notes of phone number
+        from the SMS Center, or tried to be delivered to the SMS Center
+        is rejected. See notes of phone number
         format from numhash.h header file. NOTE: the system has only
         a precision of last 9 or 18 digits of phone numbers, so
         beware!
      </entry></row>
 
+     <row><entry><literal>white-list-regex</literal></entry>
+        <entry>POSIX regular expression</entry>
+        <entry valign="bottom">
+        A regular expression defining the set of accepted senders.
+        See section on <xref linkend="regular-expressions"/> for details.
+        </entry>   
+     </row>
+
     <row><entry><literal>black-list</literal></entry>
      <entry>URL</entry>
      <entry valign="bottom">
-        As white-list, but SMS messages to these numbers are
-        automatically discarded
+        As white-list, but SMS messages from these sender numbers are
+        automatically rejected.
      </entry></row>
 
+     <row><entry><literal>black-list-regex</literal></entry>
+        <entry>POSIX regular expression</entry>
+        <entry valign="bottom">
+        A regular expression defining the set of rejected senders.
+        See section on <xref linkend="regular-expressions"/> for details.
+        </entry>   
+     </row>
+
+    <row><entry><literal>white-list-receiver</literal></entry>
+     <entry>URL</entry>
+     <entry valign="bottom">
+        Load a list of accepted receiver of SMS messages. If a receiver
+        of an SMS message is not in this list, any message received
+        from the SMS Center, or tried to be delivered to the SMS Center
+        is rejected. See notes of phone number
+        format from numhash.h header file. NOTE: the system has only
+        a precision of last 9 or 18 digits of phone numbers, so
+        beware!
+     </entry></row>
+
+     <row><entry><literal>white-list-receiver-regex</literal></entry>
+        <entry>POSIX regular expression</entry>
+        <entry valign="bottom">
+        A regular expression defining the set of accepted receivers.
+        See section on <xref linkend="regular-expressions"/> for details.
+        </entry>   
+     </row>
+
+    <row><entry><literal>black-list-receiver</literal></entry>
+     <entry>URL</entry>
+     <entry valign="bottom">
+        As white-list, but SMS messages from these receiver numbers are
+        automatically rejected.
+     </entry></row>
+
+     <row><entry><literal>black-list-receiver-regex</literal></entry>
+        <entry>POSIX regular expression</entry>
+        <entry valign="bottom">
+        A regular expression defining the set of rejected receivers.
+        See section on <xref linkend="regular-expressions"/> for details.
+        </entry>   
+     </row>
+
     <row><entry><literal>store-type</literal></entry>
      <entry>filename</entry>
      <entry valign="bottom">
@@ -1569,21 +1621,6 @@
         The default value, 1 million, works for most installations.
      </entry></row>
 
-     <row><entry><literal>white-list-regex</literal></entry>
-        <entry>POSIX regular expression</entry>
-        <entry valign="bottom">
-        A regular expression defining the set of accepted senders.
-        See section on <xref linkend="regular-expressions"/> for details.
-        </entry>   
-     </row>
-     <row><entry><literal>black-list-regex</literal></entry>
-        <entry>POSIX regular expression</entry>
-        <entry valign="bottom">
-        A regular expression defining the set of rejected senders.
-        See section on <xref linkend="regular-expressions"/> for details.
-        </entry>   
-     </row>
-
      <row><entry><literal>smsbox-max-pending</literal></entry>
         <entry>number of messages</entry>
         <entry valign="bottom">
Index: gw/bb_boxc.c
===================================================================
--- gw/bb_boxc.c	(revision 5097)
+++ gw/bb_boxc.c	(working copy)
@@ -279,6 +279,15 @@
             msg_destroy(msg);
             break;
 
+        case SMSCCONN_FAILED_REJECTED:      /* white/black-list rejection */
+            warning(0, "Message rejected by bearerbox, white/black listed!");
+
+            mack->ack.nack = ack_failed;
+
+            /* destroy original message */
+            msg_destroy(msg);
+            break;
+
         default:
             break;
     }
Index: gw/bb_smscconn.c
===================================================================
--- gw/bb_smscconn.c	(revision 5097)
+++ gw/bb_smscconn.c	(working copy)
@@ -133,11 +133,17 @@
 static RWLock white_black_list_lock;
 static Octstr *black_list_url;
 static Octstr *white_list_url;
+static Octstr *black_list_receiver_url;
+static Octstr *white_list_receiver_url;
 static Numhash *black_list;
 static Numhash *white_list;
+static Numhash *black_list_receiver;
+static Numhash *white_list_receiver;
 
 static regex_t *white_list_regex;
 static regex_t *black_list_regex;
+static regex_t *white_list_receiver_regex;
+static regex_t *black_list_receiver_regex;
 
 static long router_thread = -1;
 
@@ -370,6 +376,12 @@
             else
                 bb_alog_sms(conn, sms, "EXPIRED DLR");
         }
+        else if (reason == SMSCCONN_FAILED_REJECTED) {
+            if (sms->sms.sms_type != report_mt)
+                bb_alog_sms(conn, sms, "REJECTED Send SMS");
+            else
+                bb_alog_sms(conn, sms, "REJECTED Send DLR");
+        }
         else {
             if (sms->sms.sms_type != report_mt)
                 bb_alog_sms(conn, sms, "FAILED Send SMS");
@@ -423,48 +435,96 @@
     uf = unified_prefix ? octstr_get_cstr(unified_prefix) : NULL;
     normalize_number(uf, &(sms->sms.sender));
 
-    gw_rwlock_rdlock(&white_black_list_lock);
-    if (white_list && numhash_find_number(white_list, sms->sms.sender) < 1) {
-        gw_rwlock_unlock(&white_black_list_lock);
-        info(0, "Number <%s> is not in white-list, message discarded",
-             octstr_get_cstr(sms->sms.sender));
-        bb_alog_sms(conn, sms, "REJECTED - not white-listed SMS");
-        msg_destroy(sms);
-        return SMSCCONN_FAILED_REJECTED;
-    }
+    /*
+     * We don't perform white/black-listing for DLRs.
+     * Fix fix sms type if not set already.
+     */
+    if (sms->sms.sms_type != report_mo) {
+        sms->sms.sms_type = mo;
 
-    if (white_list_regex && gw_regex_match_pre(white_list_regex, sms->sms.sender) == 0) {
-        gw_rwlock_unlock(&white_black_list_lock);
-        info(0, "Number <%s> is not in white-list, message discarded",
-             octstr_get_cstr(sms->sms.sender));
-        bb_alog_sms(conn, sms, "REJECTED - not white-regex-listed SMS");
-        msg_destroy(sms);
-        return SMSCCONN_FAILED_REJECTED;
-    }
-    
-    if (black_list && numhash_find_number(black_list, sms->sms.sender) == 1) {
-        gw_rwlock_unlock(&white_black_list_lock);
-        info(0, "Number <%s> is in black-list, message discarded",
-             octstr_get_cstr(sms->sms.sender));
-        bb_alog_sms(conn, sms, "REJECTED - black-listed SMS");
-        msg_destroy(sms);
-        return SMSCCONN_FAILED_REJECTED;
-    }
+        gw_rwlock_rdlock(&white_black_list_lock);
+        if (white_list &&
+                numhash_find_number(white_list, sms->sms.sender) < 1) {
+            gw_rwlock_unlock(&white_black_list_lock);
+            info(0, "Number <%s> is not in white-list, message discarded",
+                 octstr_get_cstr(sms->sms.sender));
+            bb_alog_sms(conn, sms, "REJECTED Receive SMS - not white-listed SMS");
+            msg_destroy(sms);
+            return SMSCCONN_FAILED_REJECTED;
+        }
 
-    if (black_list_regex && gw_regex_match_pre(black_list_regex, sms->sms.sender) == 0) {
+        if (white_list_regex &&
+                gw_regex_match_pre(white_list_regex, sms->sms.sender) == 0) {
+            gw_rwlock_unlock(&white_black_list_lock);
+            info(0, "Number <%s> is not in white-list, message discarded",
+                 octstr_get_cstr(sms->sms.sender));
+            bb_alog_sms(conn, sms, "REJECTED Receive SMS - not white-regex-listed SMS");
+            msg_destroy(sms);
+            return SMSCCONN_FAILED_REJECTED;
+        }
+
+        if (black_list &&
+                numhash_find_number(black_list, sms->sms.sender) == 1) {
+            gw_rwlock_unlock(&white_black_list_lock);
+            info(0, "Number <%s> is in black-list, message discarded",
+                 octstr_get_cstr(sms->sms.sender));
+            bb_alog_sms(conn, sms, "REJECTED Receive SMS - black-listed SMS");
+            msg_destroy(sms);
+            return SMSCCONN_FAILED_REJECTED;
+        }
+
+        if (black_list_regex &&
+                gw_regex_match_pre(black_list_regex, sms->sms.sender) == 0) {
+            gw_rwlock_unlock(&white_black_list_lock);
+            info(0, "Number <%s> is not in black-list, message discarded",
+                 octstr_get_cstr(sms->sms.sender));
+            bb_alog_sms(conn, sms, "REJECTED Receive SMS - black-regex-listed SMS");
+            msg_destroy(sms);
+            return SMSCCONN_FAILED_REJECTED;
+        }
+
+        if (white_list_receiver &&
+                numhash_find_number(white_list_receiver, sms->sms.receiver) < 1) {
+            gw_rwlock_unlock(&white_black_list_lock);
+            info(0, "Number <%s> is not in white-list-receiver, message discarded",
+                 octstr_get_cstr(sms->sms.receiver));
+            bb_alog_sms(conn, sms, "REJECTED Receive SMS - not white-listed SMS");
+            msg_destroy(sms);
+            return SMSCCONN_FAILED_REJECTED;
+        }
+
+        if (white_list_receiver_regex &&
+                gw_regex_match_pre(white_list_receiver_regex, sms->sms.receiver) == 0) {
+            gw_rwlock_unlock(&white_black_list_lock);
+            info(0, "Number <%s> is not in white-list-receiver, message discarded",
+                 octstr_get_cstr(sms->sms.receiver));
+            bb_alog_sms(conn, sms, "REJECTED Receive SMS - not white-regex-listed SMS");
+            msg_destroy(sms);
+            return SMSCCONN_FAILED_REJECTED;
+        }
+
+        if (black_list_receiver &&
+                numhash_find_number(black_list_receiver, sms->sms.receiver) == 1) {
+            gw_rwlock_unlock(&white_black_list_lock);
+            info(0, "Number <%s> is in black-list-receiver, message discarded",
+                 octstr_get_cstr(sms->sms.receiver));
+            bb_alog_sms(conn, sms, "REJECTED Receive SMS - black-listed SMS");
+            msg_destroy(sms);
+            return SMSCCONN_FAILED_REJECTED;
+        }
+
+        if (black_list_receiver_regex &&
+                gw_regex_match_pre(black_list_receiver_regex, sms->sms.receiver) == 0) {
+            gw_rwlock_unlock(&white_black_list_lock);
+            info(0, "Number <%s> is not in black-list-receiver, message discarded",
+                 octstr_get_cstr(sms->sms.receiver));
+            bb_alog_sms(conn, sms, "REJECTED Receive SMS - black-regex-listed SMS");
+            msg_destroy(sms);
+            return SMSCCONN_FAILED_REJECTED;
+        }
         gw_rwlock_unlock(&white_black_list_lock);
-        info(0, "Number <%s> is not in black-list, message discarded",
-             octstr_get_cstr(sms->sms.sender));
-        bb_alog_sms(conn, sms, "REJECTED - black-regex-listed SMS");
-        msg_destroy(sms);
-        return SMSCCONN_FAILED_REJECTED;
     }
-    gw_rwlock_unlock(&white_black_list_lock);
 
-    /* fix sms type if not set already */
-    if (sms->sms.sms_type != report_mo)
-        sms->sms.sms_type = mo;
-
     /* write to store (if enabled) */
     if (store_save(sms) == -1) {
         msg_destroy(sms);
@@ -721,6 +781,32 @@
         octstr_destroy(os);
     }
 
+    white_list_receiver = black_list_receiver = NULL;
+    white_list_receiver_url = black_list_receiver_url = NULL;
+    white_list_receiver_url = cfg_get(grp, octstr_imm("white-list-receiver"));
+    if (white_list_receiver_url != NULL) {
+        if ((white_list_receiver = numhash_create(octstr_get_cstr(white_list_receiver_url))) == NULL)
+            panic(0, "Could not get white-list-receiver at URL <%s>",
+                  octstr_get_cstr(white_list_receiver_url));
+    }
+    if ((os = cfg_get(grp, octstr_imm("white-list-receiver-regex"))) != NULL) {
+        if ((white_list_receiver_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL)
+            panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os));
+        octstr_destroy(os);
+    }
+
+    black_list_receiver_url = cfg_get(grp, octstr_imm("black-list-receiver"));
+    if (black_list_receiver_url != NULL) {
+        if ((black_list_receiver = numhash_create(octstr_get_cstr(black_list_receiver_url))) == NULL)
+            panic(0, "Could not get black-list-receiver at URL <%s>",
+                  octstr_get_cstr(black_list_receiver_url));
+    }
+    if ((os = cfg_get(grp, octstr_imm("black-list-receiver-regex"))) != NULL) {
+        if ((black_list_receiver_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL)
+            panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os));
+        octstr_destroy(os);
+    }
+
     if (cfg_get_integer(&sms_resend_frequency, grp,
             octstr_imm("sms-resend-freq")) == -1 || sms_resend_frequency <= 0) {
         sms_resend_frequency = 60;
@@ -1018,6 +1104,32 @@
         }
     }
 
+    if (white_list_receiver_url != NULL) {
+        tmp = numhash_create(octstr_get_cstr(white_list_receiver_url));
+        if (white_list_receiver == NULL) {
+            error(0, "Unable to reload white_list."),
+            rc = -1;
+        } else {
+            gw_rwlock_wrlock(&white_black_list_lock);
+            numhash_destroy(white_list_receiver);
+            white_list_receiver = tmp;
+            gw_rwlock_unlock(&white_black_list_lock);
+        }
+    }
+
+    if (black_list_receiver_url != NULL) {
+        tmp = numhash_create(octstr_get_cstr(black_list_receiver_url));
+        if (black_list_receiver == NULL) {
+            error(0, "Unable to reload black_list");
+            rc = -1;
+        } else {
+            gw_rwlock_wrlock(&white_black_list_lock);
+            numhash_destroy(black_list_receiver);
+            black_list = tmp;
+            gw_rwlock_unlock(&white_black_list_lock);
+        }
+    }
+
     return rc;
 }
 
@@ -1126,6 +1238,14 @@
         gw_regex_destroy(white_list_regex);
     if (black_list_regex != NULL)
         gw_regex_destroy(black_list_regex);
+    numhash_destroy(white_list_receiver);
+    numhash_destroy(black_list_receiver);
+    octstr_destroy(white_list_receiver_url);
+    octstr_destroy(black_list_receiver_url);
+    if (white_list_receiver_regex != NULL)
+        gw_regex_destroy(white_list_receiver_regex);
+    if (black_list_receiver_regex != NULL)
+        gw_regex_destroy(black_list_receiver_regex);
     /* destroy msg split counter */
     counter_destroy(split_msg_counter);
     gw_rwlock_destroy(&smsc_list_lock);
@@ -1320,7 +1440,7 @@
  */
 long smsc2_rout(Msg *msg, int resend)
 {
-    StatusInfo info;
+    StatusInfo stat;
     SMSCConn *conn, *best_preferred, *best_ok;
     long bp_load, bo_load;
     int i, s, ret, bad_found, full_found;
@@ -1341,10 +1461,76 @@
 
     /* unify prefix of receiver, in case of it has not been
      * already done */
-
     uf = unified_prefix ? octstr_get_cstr(unified_prefix) : NULL;
     normalize_number(uf, &(msg->sms.receiver));
 
+    /* check for white/back-listed sender/receiver */
+    gw_rwlock_rdlock(&white_black_list_lock);
+    if (white_list && numhash_find_number(white_list, msg->sms.sender) < 1) {
+        gw_rwlock_unlock(&white_black_list_lock);
+        info(0, "Number <%s> is not in white-list, message rejected",
+             octstr_get_cstr(msg->sms.sender));
+        bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("sender not in white-list"));
+        return SMSCCONN_FAILED_REJECTED;
+    }
+
+    if (white_list_regex && gw_regex_match_pre(white_list_regex, msg->sms.sender) == 0) {
+        gw_rwlock_unlock(&white_black_list_lock);
+        info(0, "Number <%s> is not in white-list, message rejected",
+             octstr_get_cstr(msg->sms.sender));
+        bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("sender not in white-list"));
+        return SMSCCONN_FAILED_REJECTED;
+    }
+
+    if (black_list && numhash_find_number(black_list, msg->sms.sender) == 1) {
+        gw_rwlock_unlock(&white_black_list_lock);
+        info(0, "Number <%s> is in black-list, message rejected",
+             octstr_get_cstr(msg->sms.sender));
+        bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("sender in black-list"));
+        return SMSCCONN_FAILED_REJECTED;
+    }
+
+    if (black_list_regex && gw_regex_match_pre(black_list_regex, msg->sms.sender) == 0) {
+        gw_rwlock_unlock(&white_black_list_lock);
+        info(0, "Number <%s> is not in black-list, message rejected",
+             octstr_get_cstr(msg->sms.sender));
+        bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("sender in black-list"));
+        return SMSCCONN_FAILED_REJECTED;
+    }
+
+    if (white_list_receiver && numhash_find_number(white_list_receiver, msg->sms.receiver) < 1) {
+        gw_rwlock_unlock(&white_black_list_lock);
+        info(0, "Number <%s> is not in white-list-receiver, message rejected",
+             octstr_get_cstr(msg->sms.receiver));
+        bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("receiver not in white-list"));
+        return SMSCCONN_FAILED_REJECTED;
+    }
+
+    if (white_list_receiver_regex && gw_regex_match_pre(white_list_receiver_regex, msg->sms.receiver) == 0) {
+        gw_rwlock_unlock(&white_black_list_lock);
+        info(0, "Number <%s> is not in white-list-receiver, message rejected",
+             octstr_get_cstr(msg->sms.receiver));
+        bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("receiver not in white-list"));
+        return SMSCCONN_FAILED_REJECTED;
+    }
+
+    if (black_list_receiver && numhash_find_number(black_list_receiver, msg->sms.receiver) == 1) {
+        gw_rwlock_unlock(&white_black_list_lock);
+        info(0, "Number <%s> is in black-list-receiver, message rejected",
+             octstr_get_cstr(msg->sms.receiver));
+        bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("receiver in black-list"));
+        return SMSCCONN_FAILED_REJECTED;
+    }
+
+    if (black_list_receiver_regex && gw_regex_match_pre(black_list_receiver_regex, msg->sms.receiver) == 0) {
+        gw_rwlock_unlock(&white_black_list_lock);
+        info(0, "Number <%s> is not in black-list-receiver, message rejected",
+             octstr_get_cstr(msg->sms.receiver));
+        bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("receiver in black-list"));
+        return SMSCCONN_FAILED_REJECTED;
+    }
+    gw_rwlock_unlock(&white_black_list_lock);
+
     /* select in which list to add this
      * start - from random SMSCConn, as they are all 'equal'
      */
@@ -1377,8 +1563,8 @@
     	for (i = 0; i < gwlist_len(smsc_list); i++) {
     		conn = gwlist_get(smsc_list,  (i+s) % gwlist_len(smsc_list));
 
-    		smscconn_info(conn, &info);
-    		queue_length += (info.queued > 0 ? info.queued : 0);
+    		smscconn_info(conn, &stat);
+    		queue_length += (stat.queued > 0 ? stat.queued : 0);
 
     		ret = smscconn_usable(conn,msg);
     		if (ret == -1)
@@ -1389,25 +1575,25 @@
     			continue;
 
     		/* If connection is not currently answering ... */
-    		if (info.status != SMSCCONN_ACTIVE) {
+    		if (stat.status != SMSCCONN_ACTIVE) {
     			bad_found = 1;
     			continue;
     		}
     		/* check queue length */
-    		if (info.queued > max_queue) {
+    		if (stat.queued > max_queue) {
     			full_found = 1;
     			continue;
     		}
     		if (ret == 1) {          /* preferred */
-    			if (best_preferred == NULL || info.load < bp_load) {
+    			if (best_preferred == NULL || stat.load < bp_load) {
     				best_preferred = conn;
-    				bp_load = info.load;
+    				bp_load = stat.load;
     				continue;
     			}
     		}
-    		if (best_ok == NULL || info.load < bo_load) {
+    		if (best_ok == NULL || stat.load < bo_load) {
     			best_ok = conn;
-    			bo_load = info.load;
+    			bo_load = stat.load;
     		}
     	}
     	queue_length += gwlist_len(outgoing_sms);
Index: gwlib/cfg.def
===================================================================
--- gwlib/cfg.def	(revision 5097)
+++ gwlib/cfg.def	(working copy)
@@ -110,6 +110,10 @@
     OCTSTR(white-list-regex)
     OCTSTR(black-list)
     OCTSTR(black-list-regex)
+    OCTSTR(white-list-receiver)
+    OCTSTR(white-list-receiver-regex)
+    OCTSTR(black-list-receiver)
+    OCTSTR(black-list-receiver-regex)
     OCTSTR(http-proxy-host)
     OCTSTR(http-proxy-port)
     OCTSTR(http-proxy-ssl)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.