311 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			311 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include "c_types.h"
 | 
						|
#include "mem.h"
 | 
						|
#include "ets_sys.h"
 | 
						|
#include "osapi.h"
 | 
						|
#include "os_type.h"
 | 
						|
#include "lwip/ip.h"
 | 
						|
#include "lwip/udp.h"
 | 
						|
#include "lwip/tcp_impl.h"
 | 
						|
#include "netif/etharp.h"
 | 
						|
 | 
						|
#include "user_interface.h"
 | 
						|
#include "string.h"
 | 
						|
 | 
						|
#include "acl.h"
 | 
						|
 | 
						|
acl_entry acl[MAX_NO_ACLS][MAX_ACL_ENTRIES];
 | 
						|
uint8_t acl_freep[MAX_NO_ACLS];
 | 
						|
uint32_t acl_allow_count;
 | 
						|
uint32_t acl_deny_count;
 | 
						|
static packet_deny_cb my_deny_cb;
 | 
						|
 | 
						|
void ICACHE_FLASH_ATTR
 | 
						|
acl_init()
 | 
						|
{
 | 
						|
  int i;
 | 
						|
  acl_allow_count = acl_deny_count = 0;
 | 
						|
  my_deny_cb = NULL;
 | 
						|
  for(i=0; i< MAX_NO_ACLS; i++)
 | 
						|
  {
 | 
						|
    acl_freep[i] = 0;
 | 
						|
    acl_clear_stats(i);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool ICACHE_FLASH_ATTR
 | 
						|
acl_is_empty(uint8_t acl_no)
 | 
						|
{
 | 
						|
  if (acl_no >= MAX_NO_ACLS)
 | 
						|
  {
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
  return acl_freep[acl_no] == 0;
 | 
						|
}
 | 
						|
 | 
						|
void ICACHE_FLASH_ATTR
 | 
						|
acl_clear(uint8_t acl_no)
 | 
						|
{
 | 
						|
  if (acl_no >= MAX_NO_ACLS)
 | 
						|
  {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  acl_freep[acl_no] = 0;
 | 
						|
  acl_clear_stats(acl_no);
 | 
						|
}
 | 
						|
 | 
						|
void ICACHE_FLASH_ATTR
 | 
						|
acl_clear_stats(uint8_t acl_no)
 | 
						|
{
 | 
						|
  int i;
 | 
						|
 | 
						|
  if (acl_no >= MAX_NO_ACLS)
 | 
						|
  {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  my_deny_cb = NULL;
 | 
						|
  for(i=0; i< MAX_ACL_ENTRIES; i++)
 | 
						|
  acl[acl_no][i].hit_count = 0;
 | 
						|
}
 | 
						|
 | 
						|
bool ICACHE_FLASH_ATTR
 | 
						|
acl_add(uint8_t acl_no,
 | 
						|
        uint32_t src,
 | 
						|
        uint32_t s_mask,
 | 
						|
        uint32_t dest,
 | 
						|
        uint32_t d_mask,
 | 
						|
        uint8_t proto,
 | 
						|
        uint16_t s_port,
 | 
						|
        uint16_t d_port,
 | 
						|
        uint8_t allow)
 | 
						|
{
 | 
						|
  acl_entry *my_entry;
 | 
						|
 | 
						|
  if (acl_no >= MAX_NO_ACLS || acl_freep[acl_no] >= MAX_ACL_ENTRIES)
 | 
						|
  {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  my_entry = &acl[acl_no][acl_freep[acl_no]];
 | 
						|
  my_entry->src = src & s_mask;
 | 
						|
  my_entry->s_mask = s_mask;
 | 
						|
  my_entry->dest = dest & d_mask;
 | 
						|
  my_entry->d_mask = d_mask;
 | 
						|
  my_entry->proto = proto;
 | 
						|
  my_entry->s_port = s_port;
 | 
						|
  my_entry->d_port = d_port;
 | 
						|
  my_entry->allow = allow;
 | 
						|
  my_entry->hit_count = 0;
 | 
						|
 | 
						|
  acl_freep[acl_no]++;
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t ICACHE_FLASH_ATTR
 | 
						|
acl_check_packet(uint8_t acl_no, struct pbuf *p)
 | 
						|
{
 | 
						|
  struct eth_hdr *mac_h;
 | 
						|
  struct ip_hdr *ip_h;
 | 
						|
  uint8_t proto;
 | 
						|
  struct udp_hdr *udp_h;
 | 
						|
  struct tcp_hdr *tcp_h;
 | 
						|
  uint16_t src_port, dest_port;
 | 
						|
  uint8_t *packet;
 | 
						|
  int i;
 | 
						|
  acl_entry *my_entry;
 | 
						|
  uint8_t allow;
 | 
						|
 | 
						|
  if (acl_no >= MAX_NO_ACLS)
 | 
						|
  {
 | 
						|
    return ACL_DENY;
 | 
						|
  }
 | 
						|
 | 
						|
  if (p->len < sizeof(struct eth_hdr))
 | 
						|
  {
 | 
						|
    return ACL_DENY;
 | 
						|
  }
 | 
						|
 | 
						|
  mac_h = (struct eth_hdr *)p->payload;
 | 
						|
 | 
						|
  // Allow ARP
 | 
						|
  if (ntohs(mac_h->type) == ETHTYPE_ARP)
 | 
						|
  {
 | 
						|
    acl_allow_count++;
 | 
						|
    return ACL_ALLOW;
 | 
						|
  }
 | 
						|
 | 
						|
  // Drop anything else if not IPv4
 | 
						|
  if (ntohs(mac_h->type) != ETHTYPE_IP)
 | 
						|
  {
 | 
						|
    acl_deny_count++;
 | 
						|
    return ACL_DENY;
 | 
						|
  }
 | 
						|
 | 
						|
  if (p->len < sizeof(struct eth_hdr)+sizeof(struct ip_hdr))
 | 
						|
  {
 | 
						|
    acl_deny_count++;
 | 
						|
    return ACL_DENY;
 | 
						|
  }
 | 
						|
 | 
						|
  allow = ACL_DENY;
 | 
						|
  packet = (uint8_t*)p->payload;
 | 
						|
  ip_h = (struct ip_hdr *)&packet[sizeof(struct eth_hdr)];
 | 
						|
  proto = IPH_PROTO(ip_h);
 | 
						|
 | 
						|
  switch (proto) {
 | 
						|
    case IP_PROTO_UDP:
 | 
						|
    {
 | 
						|
      if (p->len < sizeof(struct eth_hdr)+sizeof(struct ip_hdr)+sizeof(struct udp_hdr))
 | 
						|
      {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      udp_h = (struct udp_hdr *)&packet[sizeof(struct eth_hdr)+sizeof(struct ip_hdr)];
 | 
						|
      src_port = ntohs(udp_h->src);
 | 
						|
      dest_port = ntohs(udp_h->dest);
 | 
						|
    } break;
 | 
						|
 | 
						|
    case IP_PROTO_TCP:
 | 
						|
    {
 | 
						|
      if (p->len < sizeof(struct eth_hdr)+sizeof(struct ip_hdr)+sizeof(struct tcp_hdr))
 | 
						|
      {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      tcp_h = (struct tcp_hdr *)&packet[sizeof(struct eth_hdr)+sizeof(struct ip_hdr)];
 | 
						|
      src_port = ntohs(tcp_h->src);
 | 
						|
      dest_port = ntohs(tcp_h->dest);
 | 
						|
    } break;
 | 
						|
 | 
						|
    case IP_PROTO_ICMP:
 | 
						|
    {
 | 
						|
      src_port = dest_port = 0;
 | 
						|
    } break;
 | 
						|
 | 
						|
    // Drop anything that is not UDP, TCP, or ICMP
 | 
						|
    default:
 | 
						|
    {
 | 
						|
      acl_deny_count++;
 | 
						|
      return ACL_DENY;
 | 
						|
    } break;
 | 
						|
  }
 | 
						|
 | 
						|
  //    os_printf("Src: %d.%d.%d.%d Dst: %d.%d.%d.%d Proto: %s SP:%d DP:%d\n",
 | 
						|
  //		IP2STR(&ip_h->src), IP2STR(&ip_h->dest),
 | 
						|
  //		proto==IP_PROTO_TCP?"TCP":proto==IP_PROTO_UDP?"UDP":"IP4", src_port, dest_port);
 | 
						|
 | 
						|
  for(i=0; i<acl_freep[acl_no]; i++)
 | 
						|
  {
 | 
						|
    my_entry = &acl[acl_no][i];
 | 
						|
    if ((my_entry->proto == 0  || proto == my_entry->proto) &&
 | 
						|
        (my_entry->src == 0    || my_entry->src == (ip_h->src.addr&my_entry->s_mask)) &&
 | 
						|
        (my_entry->dest == 0   || my_entry->dest == (ip_h->dest.addr&my_entry->d_mask)) &&
 | 
						|
        (my_entry->s_port == 0 || my_entry->s_port == src_port) &&
 | 
						|
        (my_entry->d_port == 0 || my_entry->d_port == dest_port))
 | 
						|
    {
 | 
						|
      allow = my_entry->allow;
 | 
						|
      my_entry->hit_count++;
 | 
						|
      goto done;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
done:
 | 
						|
  if (!(allow & ACL_ALLOW) && my_deny_cb != NULL)
 | 
						|
  {
 | 
						|
    allow = my_deny_cb(proto, ip_h->src.addr, src_port,
 | 
						|
                       ip_h->dest.addr, dest_port, allow);
 | 
						|
  }
 | 
						|
  if (allow & ACL_ALLOW)
 | 
						|
  {
 | 
						|
    acl_allow_count++;
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    acl_deny_count++;
 | 
						|
  }
 | 
						|
 | 
						|
  // os_printf(" allow: %d\r\n",  allow);
 | 
						|
  return allow;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
acl_set_deny_cb(packet_deny_cb cb)
 | 
						|
{
 | 
						|
  my_deny_cb = cb;
 | 
						|
}
 | 
						|
 | 
						|
void ICACHE_FLASH_ATTR
 | 
						|
addr2str(uint8_t *buf, uint32_t addr, uint32_t mask)
 | 
						|
{
 | 
						|
  uint8_t clidr;
 | 
						|
 | 
						|
  if (addr == 0)
 | 
						|
  {
 | 
						|
    os_sprintf(buf, "any");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  mask = ntohl(mask);
 | 
						|
  for (clidr = 0; mask; mask <<= 1,clidr++);
 | 
						|
  if (clidr < 32)
 | 
						|
  {
 | 
						|
    os_sprintf(buf, "%d.%d.%d.%d/%d", IP2STR((ip_addr_t*)&addr), clidr);
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    os_sprintf(buf, "%d.%d.%d.%d", IP2STR((ip_addr_t*)&addr));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ICACHE_FLASH_ATTR
 | 
						|
port2str(uint8_t *buf, uint16_t port)
 | 
						|
{
 | 
						|
  if (port == 0)
 | 
						|
  {
 | 
						|
    os_sprintf(buf, "any");
 | 
						|
  }
 | 
						|
  else
 | 
						|
  {
 | 
						|
    os_sprintf(buf, "%d", port);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ICACHE_FLASH_ATTR
 | 
						|
acl_show(uint8_t acl_no, uint8_t *buf)
 | 
						|
{
 | 
						|
  int i;
 | 
						|
  acl_entry *my_entry;
 | 
						|
  uint8_t line[80], addr1[21], addr2[21], port1[6], port2[6];
 | 
						|
 | 
						|
  buf[0] = 0;
 | 
						|
 | 
						|
  if (acl_no >= MAX_NO_ACLS)
 | 
						|
  {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  for(i = 0; i < acl_freep[acl_no]; i++)
 | 
						|
  {
 | 
						|
    my_entry = &acl[acl_no][i];
 | 
						|
    addr2str(addr1, my_entry->src, my_entry->s_mask);
 | 
						|
    port2str(port1, my_entry->s_port);
 | 
						|
    addr2str(addr2, my_entry->dest, my_entry->d_mask);
 | 
						|
    port2str(port2, my_entry->d_port);
 | 
						|
    if (my_entry->proto != 0)
 | 
						|
    {
 | 
						|
      os_sprintf(line, "%s %s:%s %s:%s %s%s (%d hits)\r\n",
 | 
						|
      my_entry->proto==IP_PROTO_TCP?"TCP":"UDP",
 | 
						|
      addr1, port1, addr2, port2,
 | 
						|
      (my_entry->allow & ACL_ALLOW)?"allow":"deny",
 | 
						|
      (my_entry->allow & ACL_MONITOR)?"_monitor":"",
 | 
						|
      my_entry->hit_count);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
      os_sprintf(line, "IP %s %s %s%s (%d hits)\r\n",
 | 
						|
      addr1, addr2,
 | 
						|
      (my_entry->allow & ACL_ALLOW)?"allow":"deny",
 | 
						|
      (my_entry->allow & ACL_MONITOR)?"_monitor":"",
 | 
						|
      my_entry->hit_count);
 | 
						|
    }
 | 
						|
    os_memcpy(&buf[os_strlen(buf)], line, os_strlen(line)+1);
 | 
						|
  }
 | 
						|
}
 |