A simple approach could be the use of Linux network namespaces.
Linux Network Namespaces
As the name would imply, network namespaces partition the use of the network—devices, addresses, ports, routes, firewall rules, etc.—into separate boxes, essentially virtualizing the network within a single running kernel instance. Network namespaces entered the kernel in 2.6.24,...
see https://lwn.net/Articles/580893/
Unshare
unshare() allows a process (or thread) to disassociate parts of its execution context that are currently being shared with other processes (or threads).
see http://man7.org/linux/man-pages/man2/unshare.2.html
Testcase
Since a program should be able to comunicate with itself we need a program that communicates with itself via sockes. There is a cool SO answer that shows a simple Java program that transfers the text 'Hello World!' via socket to itself, see here https://stackoverflow.com/a/8119708.
/usr/bin/java SendReceive
works as expected and gives the output 'Hello World!'
With the -n option one can unshare network namespace.
unshare -n -- sh -c '/usr/bin/java SendReceive'
gives a SocketException: Network is unreachable because there is no access to the loopback device.
unshare -n -- sh -c 'ip link set dev lo up; /usr/bin/java SendReceive'
finally transfers 'Hello World!' again via a loopback interface. BTW: this is a private loopback device. You cannot access open ports on the standard loopback device.
See also this cool Unix Stackexchange answer: https://unix.stackexchange.com/a/83348: Block network access of a process?
Screenshot
Here a screenshot of the test case mentioned above executed on Ubuntu 18.10:
