With LIDS, you can protect you network with some features shown below.
If you host also contains some firwall rules. you can protect them by LIDS.
You should turn the CONFIG_LIDS_ALLOW_CHANGE_ROUTES
on. And you must
turn the CAP_NET_ADMIN
off when sealing the kernel.
And then, you can also define allowed programs to change the routing rules.
Let's look at the code of Firewall rules protection. Every request
to change the firewall rules will called the kernel function ip_setsockopt()
.
int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
{
........
switch(optname)
{
.......
case IP_FW_DELETE_NUM:
case IP_FW_INSERT:
case IP_FW_FLUSH:
case IP_FW_ZERO:
case IP_FW_CHECK:
case IP_FW_CREATECHAIN:
case IP_FW_DELETECHAIN:
case IP_FW_POLICY:
#ifdef CONFIG_LIDS_ALLOW_CHANGE_ROUTES
if (!(capable(CAP_NET_ADMIN) || (current->flags & PF_CHROUTES))) {
#else
if (!capable(CAP_NET_ADMIN)) {
#endif
#ifdef CONFIG_LIDS
lids_security_alert("CAP_NET_ADMIN violation: try to change IP firewall rules with option %d",optname);
#endif
return -EACCES;
}
........
From the above code, we can see that if you want to change the firewall rules,
you must turn the capabilty CAP_NET_ADMIN
on and the program you use
to change the rules must be marked as routing_changeable
. The program name shoud be provided when the configurate the kernel.
The feature is inpletemented as the above changing_route, let's have a look
at the code at net/core/dev.c
.
int dev_ioctl(unsigned int cmd, void *arg)
{
........
switch(cmd)
{
........
case SIOCSIFMETRIC:
case SIOCSIFMTU:
case SIOCSIFMAP:
case SIOCSIFHWADDR:
case SIOCSIFSLAVE:
case SIOCADDMULTI:
case SIOCDELMULTI:
case SIOCSIFHWBROADCAST:
case SIOCSIFTXQLEN:
case SIOCSIFNAME:
#ifdef CONFIG_LIDS_ALLOW_CHANGE_ROUTES
if (!(capable(CAP_NET_ADMIN) || (current->flags & PF_CHROUTES))) {
#else
if (!capable(CAP_NET_ADMIN)) {
#endif
#ifdef CONFIG_LIDS
lids_security_alert("CAP_NET_ADMIN violation: ioctl SIOC #%i",cmd);
#endif
return -EPERM;
.........
You can see that if you want to change the promiscous state needed for sniffer,
you must have capability CAP_NET_ADMIN
on and a corrent program.
You should disable the promiscouse state when the network bring up before
sealing the kernel and make the CAP_NET_ADMIN
off when sealing the kernel.
Since if a port scanner can detect half open scanning, it must be run as a sniffer packet program. If we need a port scanner and we also want the kernel disable promicouse which means that we can not use the sniffer packet programi, the port scanner detector in kernel will be useful.
The main idea for the port scanner is that it use the feature that port scanner alway scanner a rang of ports in a few seconds. And they report the opened port after scan. In this way, the scanner will scan many port which do not listen in the remote machine. In the kernel, we can detect in the following code.
Let's have a look at the tcp port scanner.
/* in net/ipv4/tcp_ipv4.c */
int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
{
........
__skb_queue_tail(&sk->back_log, skb);
return 0;
no_tcp_socket:
#ifdef CONFIG_LIDS
lids_check_scan(skb->nh.iph->saddr,ntohs(th->dest));
#endif
tcp_v4_send_reset(skb);
discard_it:
.........
}
The lids_check_scan()
take two parameters, one for the source address which
cause the no_sock_error
, the other is the port on the machine which
the source address want to communicate with but is not open for server.
The main task of the lids_check_scan()
is to statistic the error number
made from the same source. But lids_check_scan()
do not check if the source
address is a port scanner, it let the timer to do it.
Now, let's have a look at the lids_check_scan()
.
/* in net/ipv4/lids_check_scan.c */
int lids_check_scan(__u32 addr,__u16 port)
{
...........
if((p = lids_find_scan(addr)) == NULL) {
p1 = &lids_scan_head;
p = (struct lids_scan*)kmalloc(sizeof(struct lids_scan),GFP_ATOMIC);
if(p == NULL ) {
return -1;
}
while((p1->next)!=NULL)p1=p1->next;
/* init the structure. */
p1->next = p;
spin_unlock(p->lock);
p->next = NULL;
p->addr = addr;
p->counter = 0;
p->lower_counter = 0;
p->create_time = current_time;
/* init a timer to do the detect thing */
init_timer(&(p->timer));
p->timer.expires = LIDS_SCAN_TIMEOUT + current_time;
p->timer.data = (unsigned long) p;
p->timer.function = lids_proceed_scan ;
add_timer(&(p->timer));
}
/* add the counter when hit */
spin_lock(p->lock);
(p->counter)++;
/* we here defined the port < 1024 and > 1024 */
if(port < 1024)
(p->lower_counter)++;
spin_unlock(p->lock);
return 0;
}
From the above code, we can see the the function just maintant the list
, so it is faster. In order to prevent the DoS attack on the kmalloc(),
we also need to limited the detected list. It may be a fault in this
code, but since the timer function -- lids_proceed_scan
update
the list very fast -- every 3 second once. So the DoS attack is every
difficult to make the kernel confuse about which is the true scaner source.