gb: optionally allow nsip packets only from a specific host

When listening for nsip connections is enabled, then every remote
host may send packets. This is useful for an SGSN that serves
multiple PCUs, but contraproductive for a PCU that awaits packets
from a single SGSN.

Add struct members remote_ip, and remote_port to struct gprs_ns_inst,
when set, then the listening end uses connect() to ensure that only
the expected host may send packets.

Related: OS#2401
Change-Id: Ifeb201d9006eec275a46708007ff342cdfc14e45
diff --git a/src/gb/gprs_ns.c b/src/gb/gprs_ns.c
index 7443a8b..fd465b4 100644
--- a/src/gb/gprs_ns.c
+++ b/src/gb/gprs_ns.c
@@ -1561,15 +1561,37 @@
 int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi)
 {
 	struct in_addr in;
+	struct in_addr remote;
+	char remote_str[INET_ADDRSTRLEN];
 	int ret;
 
 	in.s_addr = osmo_htonl(nsi->nsip.local_ip);
+	remote.s_addr = osmo_htonl(nsi->nsip.remote_ip);
 
 	nsi->nsip.fd.cb = nsip_fd_cb;
 	nsi->nsip.fd.data = nsi;
-	ret = osmo_sock_init_ofd(&nsi->nsip.fd, AF_INET, SOCK_DGRAM,
-				 IPPROTO_UDP, inet_ntoa(in),
-				 nsi->nsip.local_port, OSMO_SOCK_F_BIND);
+
+	if (nsi->nsip.remote_ip && nsi->nsip.remote_port) {
+		/* connect to ensure only we only accept packets from the
+		 * configured remote end/peer */
+		snprintf(remote_str, sizeof(remote_str), "%s", inet_ntoa(remote));
+		ret =
+		    osmo_sock_init2_ofd(&nsi->nsip.fd, AF_INET, SOCK_DGRAM,
+					IPPROTO_UDP, inet_ntoa(in),
+					nsi->nsip.local_port, remote_str,
+					nsi->nsip.remote_port, OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT);
+
+		LOGP(DNS, LOGL_NOTICE,
+		     "Listening for nsip packets from %s:%u on %s:%u\n",
+		     remote_str, nsi->nsip.remote_port, inet_ntoa(in), nsi->nsip.local_port);
+	} else {
+		/* Accept UDP packets from any source IP/Port */
+		ret = osmo_sock_init_ofd(&nsi->nsip.fd, AF_INET, SOCK_DGRAM,
+					 IPPROTO_UDP, inet_ntoa(in), nsi->nsip.local_port, OSMO_SOCK_F_BIND);
+
+		LOGP(DNS, LOGL_NOTICE, "Listening for nsip packets on %s:%u\n", inet_ntoa(in), nsi->nsip.local_port);
+	}
+
 	if (ret < 0)
 		return ret;