--- /usr/src/sys/netgraph/netflow/netflow.c.orig 2012-12-23 23:00:17.000000000 +0700 +++ /usr/src/sys/netgraph/netflow/netflow.c 2013-03-26 14:47:16.000000000 +0700 @@ -1,4 +1,5 @@ -/*- +/* + * Copyright (c) 2013 Stas Timokhin * Copyright (c) 2010-2011 Alexander V. Chernikov * Copyright (c) 2004-2005 Gleb Smirnoff * Copyright (c) 2001-2003 Roman V. Palagin @@ -92,10 +93,10 @@ #define SMALL(fle) (fle->f.packets <= 4) -MALLOC_DECLARE(M_NETFLOW_HASH); +/*MALLOC_DECLARE(M_NETFLOW_HASH);*/ MALLOC_DEFINE(M_NETFLOW_HASH, "netflow_hash", "NetFlow hash"); -static int export_add(item_p, struct flow_entry *); +static int export_add(item_p, struct flow_entry *, ascellhigh_p); static int export_send(priv_p, fib_export_p, item_p, int); static int hash_insert(priv_p, struct flow_hash_entry *, struct flow_rec *, int, uint8_t, uint8_t); @@ -260,6 +261,7 @@ { struct netflow_export_item exp; uint16_t version = fle->f.version; + ascellhigh_p ppp; if ((priv->export != NULL) && (version == IPVERSION)) { exp.item = get_export_dgram(priv, fe); @@ -272,7 +274,8 @@ return; } - if (export_add(exp.item, fle) > 0) + ppp=&(priv->astable[0][0]); + if (export_add(exp.item, fle, ppp) > 0) export_send(priv, fe, exp.item, flags); else return_export_dgram(priv, fe, exp.item, NG_QUEUE); @@ -1064,12 +1067,13 @@ /* Add export record to dgram. */ static int -export_add(item_p item, struct flow_entry *fle) +export_add(item_p item, struct flow_entry *fle, ascellhigh_p aaa ) { struct netflow_v5_export_dgram *dgram = mtod(NGI_M(item), struct netflow_v5_export_dgram *); struct netflow_v5_header *header = &dgram->header; struct netflow_v5_record *rec; + u_int8_t o1,o2,o3,o4; u_int16_t a1,a2; rec = &dgram->r[header->count]; header->count ++; @@ -1096,9 +1100,18 @@ rec->src_mask = fle->f.src_mask; rec->pad1 = 0; rec->pad2 = 0; - - /* Not supported fields. */ - rec->src_as = rec->dst_as = 0; + o1=(htonl(rec->src_addr)>>24)&0xFF; + o2=(htonl(rec->src_addr)>>16)&0xFF; + o3=(htonl(rec->src_addr)>>8)&0xFF; + o4=(htonl(rec->src_addr))&0xFF; + a1=GetAsnumber(aaa,o1,o2,o3,o4); + rec->src_as=htons(a1); + o1=(htonl(rec->dst_addr)>>24)&0xFF; + o2=(htonl(rec->dst_addr)>>16)&0xFF; + o3=(htonl(rec->dst_addr)>>8)&0xFF; + o4=(htonl(rec->dst_addr))&0xFF; + a2=GetAsnumber(aaa,o1,o2,o3,o4); + rec->dst_as=htons(a2); if (header->count == NETFLOW_V5_MAX_RECORDS) return (1); /* end of datagram */ @@ -1197,3 +1210,63 @@ callout_reset(&priv->exp_callout, (1*hz), &ng_netflow_expire, (void *)priv); } +int AddNetToAS (ascellhigh_p asn, u_int8_t i1, u_int8_t i2, u_int8_t i3, u_int8_t i4, \ + u_int8_t mask, u_int16_t asnumber) { + u_int16_t oldas; + oldas=GetAsnumber(asn,i1,i2,i3,i4); + if (oldas==asnumber) /*this net already in list, no action required*/ + return 0; + if (mask>=8 && mask<16) { /*information about nets of this size distirbutes to a lot of highlevel cells*/ + int k; + u_int8_t netmask; + netmask=0xFF<<(16-mask); + for (k=0; k<=16-mask; k++) + AddNetToAS(asn,i1,(i2&netmask)|k, i3,i4,16,asnumber); + return 0; + } + else { + if (mask>=16 && mask<=24) { + if (! asn[255*i1+i2].ptr_low) { /*first net in list*/ + MALLOC(asn[255*i1+i2].ptr_low,struct ascelllow*, sizeof(struct ascelllow),M_NETFLOW_HASH,M_NOWAIT); + asn[255*i1+i2].ptr_low->ip3=i3; + asn[255*i1+i2].ptr_low->mask=mask; + asn[255*i1+i2].ptr_low->asnumber=asnumber; + asn[255*i1+i2].ptr_low->ptrnext=NULL; + return 0; + } + else {/*not first net in list*/ + struct ascelllow* ptrlast; + MALLOC(ptrlast, struct ascelllow*,sizeof(struct ascelllow),\ + M_NETFLOW_HASH, M_NOWAIT); + ptrlast->ip3=i3; + ptrlast->asnumber=asnumber; /*add net to begin of list*/ + ptrlast->mask=mask; + ptrlast->ptrnext=asn[255*i1+i2].ptr_low; + asn[255*i1+i2].ptr_low=ptrlast; + return 0; + } + } + } + return -1; /*can't catch other network sizes (smaller than /24 and larger than /8 */ +} +u_int16_t GetAsnumber (ascellhigh_p asn, u_int8_t ip1, u_int8_t ip2, u_int8_t ip3, \ + u_int8_t ip4) { + if (asn[255*ip1+ip2].ptr_low) { + struct ascelllow* ptrlast; + u_int8_t netmask; + ptrlast=asn[255*ip1+ip2].ptr_low; + do { + netmask=ptrlast->mask-16; + netmask=0xFF<<(8-netmask); + if ( ((ptrlast->ip3)&netmask)==(ip3&netmask) ) + return (ptrlast->asnumber); + ptrlast=ptrlast->ptrnext; + } + while (ptrlast!=NULL); + return 0; + /*return (data->astable[ip1][ip2].body.ptr_low->asnumber); */ + } + else + return 0; +} + --- /usr/src/sys/netgraph/netflow/ng_netflow.c.orig 2012-12-23 23:00:17.000000000 +0700 +++ /usr/src/sys/netgraph/netflow/ng_netflow.c 2013-03-26 14:36:07.000000000 +0700 @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2013 Stas Timokhin * Copyright (c) 2010-2011 Alexander V. Chernikov * Copyright (c) 2004-2005 Gleb Smirnoff * Copyright (c) 2001-2003 Roman V. Palagin @@ -113,6 +114,35 @@ &ng_parse_struct_type, &ng_netflow_settimeouts_type_fields }; +/* Parse type for ng_netflow_addnettoas */ +static const struct ng_parse_struct_field ng_netflow_addnettoas_type_fields[] + = NG_NETFLOW_ADDNETTOAS_TYPE; +static const struct ng_parse_type ng_netflow_addnettoas_type = { + &ng_parse_struct_type, + &ng_netflow_addnettoas_type_fields +}; +/* Parse type for ng_netflow_deletenetfromas */ +static const struct ng_parse_struct_field ng_netflow_deletenetfromas_type_fields[] + = NG_NETFLOW_DELETENETFROMAS_TYPE; +static const struct ng_parse_type ng_netflow_deletenetfromas_type = { + &ng_parse_struct_type, + &ng_netflow_deletenetfromas_type_fields +}; +/* Parse type for ng_netflow_getasnumber */ +static const struct ng_parse_struct_field ng_netflow_getasnumber_type_fields[] + = NG_NETFLOW_GETASNUMBER_TYPE; +static const struct ng_parse_type ng_netflow_getasnumber_type = { + &ng_parse_struct_type, + &ng_netflow_getasnumber_type_fields +}; +/* Parse type for ng_netflow_asnumber */ +static const struct ng_parse_struct_field ng_netflow_asnumber_type_fields[] + = NG_NETFLOW_ASNUMBER_TYPE; +static const struct ng_parse_type ng_netflow_asnumber_type = { + &ng_parse_struct_type, + &ng_netflow_asnumber_type_fields +}; + /* Parse type for ng_netflow_setconfig */ static const struct ng_parse_struct_field ng_netflow_setconfig_type_fields[] @@ -211,6 +241,27 @@ NULL, &ng_netflow_v9info_type }, + { + NGM_NETFLOW_COOKIE, + NGM_NETFLOW_ADDNETTOAS, + "addnettoas", + &ng_netflow_addnettoas_type, + NULL + }, + { + NGM_NETFLOW_COOKIE, + NGM_NETFLOW_DELETENETFROMAS, + "deletenet", + &ng_netflow_deletenetfromas_type, + NULL + }, + { + NGM_NETFLOW_COOKIE, + NGM_NETFLOW_GETASNUMBER, + "getasnumber", + &ng_netflow_getasnumber_type, + &ng_netflow_asnumber_type + }, { 0 } }; @@ -235,7 +286,7 @@ ng_netflow_constructor(node_p node) { priv_p priv; - int i; + int i,k; /* Initialize private data */ priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO); @@ -263,6 +314,11 @@ /* Allocate memory and set up flow cache */ ng_netflow_cache_init(priv); + /* Initialize clear ASN table */ + for (i = 0; i < 255; i++) + for (k = 0; k < 255; k++) + priv->astable[i][k].ptr_low=0; + return (0); } @@ -552,6 +608,40 @@ break; } + case NGM_NETFLOW_ADDNETTOAS: + { + struct ng_netflow_addnettoas *set; + + if (msg->header.arglen != sizeof(struct ng_netflow_addnettoas)) + ERROUT(EINVAL); + + set = (struct ng_netflow_addnettoas *)msg->data; + AddNetToAS(&(priv->astable[0][0]),set->ipoct1,set->ipoct2,set->ipoct3,set->ipoct4,set->masklen,set->asnum); + + break; + } + case NGM_NETFLOW_DELETENETFROMAS: + { + break; + } + case NGM_NETFLOW_GETASNUMBER: + { + struct ng_netflow_getasnumber *set; + struct ng_netflow_asnumber *i; + u_int16_t returnas; + if (msg->header.arglen != sizeof(struct ng_netflow_getasnumber)) + ERROUT(EINVAL); + set = (struct ng_netflow_getasnumber *)msg->data; + + + NG_MKRESPONSE(resp, msg, sizeof(struct ng_netflow_asnumber), + M_NOWAIT); + i = (struct ng_netflow_asnumber *)resp->data; + returnas=GetAsnumber(&(priv->astable[0][0]),set->ipoct1,set->ipoct2,set->ipoct3,set->ipoct4); + memcpy((void *)i, (void *)&returnas,sizeof(returnas)); + + break; + } default: ERROUT(EINVAL); /* unknown command */ break; @@ -966,11 +1056,22 @@ static int ng_netflow_rmnode(node_p node) { + int i,k; + struct ascelllow *tmp; const priv_p priv = NG_NODE_PRIVATE(node); NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(priv->node); + for (i=0; i<255; i++) + for(k=0; k<255; k++) { + while (priv->astable[i][k].ptr_low) { + /*let's free memory of linked list*/ + tmp=priv->astable[i][k].ptr_low; + priv->astable[i][k].ptr_low = priv->astable[i][k].ptr_low->ptrnext; + free(tmp, M_NETFLOW_HASH); + } + } free(priv->fib_data, M_NETGRAPH); free(priv, M_NETGRAPH); --- /usr/src/sys/netgraph/netflow/ng_netflow.h.orig 2012-12-23 23:00:17.000000000 +0700 +++ /usr/src/sys/netgraph/netflow/ng_netflow.h 2013-03-26 14:47:50.000000000 +0700 @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2013 Stas Timokhin * Copyright (c) 2010-2011 Alexander V. Chernikov * Copyright (c) 2004-2005 Gleb Smirnoff * Copyright (c) 2001-2003 Roman V. Palagin @@ -60,6 +61,9 @@ NGM_NETFLOW_SETTEMPLATE = 8, /* set v9 flow template periodic */ NGM_NETFLOW_SETMTU = 9, /* set outgoing interface MTU */ NGM_NETFLOW_V9INFO = 10|NGM_READONLY|NGM_HASREPLY, /* get v9 info */ + NGM_NETFLOW_ADDNETTOAS = 11, /* add IP4-network/mask with AS number to table */ + NGM_NETFLOW_DELETENETFROMAS = 12, /* delete IP4-network/mask from table */ + NGM_NETFLOW_GETASNUMBER = 13 /* get AS number by IP4-address from table */ }; /* This structure is returned by the NGM_NETFLOW_INFO message */ @@ -94,6 +98,11 @@ uint32_t conf; }; +/* This structure is returned by the NGM_NETFLOW_GETASNUMBER message */ +struct ng_netflow_asnumber { + u_int16_t asnumber; +}; + /* This structure is passed to NGM_NETFLOW_SETDLT message */ struct ng_netflow_setdlt { @@ -162,6 +171,33 @@ * So beginning of these structs up to fib should be kept common. */ +#define MAXIPOCT1 255 +/* This structure is passed to NGM_NETFLOW_ADDNETTOAS*/ +struct ng_netflow_addnettoas { + u_int8_t ipoct1; + u_int8_t ipoct2; + u_int8_t ipoct3; + u_int8_t ipoct4; + u_int8_t masklen; + u_int16_t asnum; +}; +/* This structure is passed to NGM_NETFLOW_DELETENETFROMAS*/ +struct ng_netflow_deletenetfromas { + u_int8_t ipoct1; + u_int8_t ipoct2; + u_int8_t ipoct3; + u_int8_t ipoct4; + u_int8_t masklen; +}; +/* This structure is passed to NGM_NETFLOW_GETASNUMBER*/ +struct ng_netflow_getasnumber { + u_int8_t ipoct1; + u_int8_t ipoct2; + u_int8_t ipoct3; + u_int8_t ipoct4; +}; + + /* This is unique data, which identifies flow */ struct flow_rec { uint16_t flow_type; /* IPv4 L4/L3 flow, see NETFLOW_V9_FLOW* */ @@ -364,6 +400,61 @@ { NULL } \ } +/* Parse the addnettoas structure */ +#define NG_NETFLOW_ADDNETTOAS_TYPE { \ + { "oct1", &ng_parse_uint8_type }, \ + { "oct2", &ng_parse_uint8_type }, \ + { "oct3", &ng_parse_uint8_type }, \ + { "oct4", &ng_parse_uint8_type }, \ + { "mask", &ng_parse_uint8_type }, \ + { "as", &ng_parse_uint16_type },\ + { NULL } \ +} +/* Parse the deletenetfromas structure */ +#define NG_NETFLOW_DELETENETFROMAS_TYPE { \ + { "oct1", &ng_parse_uint8_type }, \ + { "oct2", &ng_parse_uint8_type }, \ + { "oct3", &ng_parse_uint8_type }, \ + { "oct4", &ng_parse_uint8_type }, \ + { "mask", &ng_parse_uint8_type }, \ + { NULL } \ +} +#define NG_NETFLOW_GETASNUMBER_TYPE { \ + { "oct1", &ng_parse_uint8_type }, \ + { "oct2", &ng_parse_uint8_type }, \ + { "oct3", &ng_parse_uint8_type }, \ + { "oct4", &ng_parse_uint8_type }, \ + { NULL } \ +} +#define NG_NETFLOW_ASNUMBER_TYPE { \ + { "as", &ng_parse_uint16_type }, \ + { NULL } \ +} + + +/* Constatants and structs for AS-filling engine*/ +#define BUSYHIGH 0x01 /*set when ip include in net /16 or larger */ +#define BUSYLOW 0x02 /*set when ip include in net /17 or smaller*/ +struct ascelllow { + u_int8_t ip3; + u_int16_t asnumber; + u_int8_t mask; + struct ascelllow* ptrnext; +}; +/*struct ascellhigh { + u_int8_t flag; + union { + struct ascelllow* ptr_low; + u_int16_t AS; + } body; +};*/ + +struct ascellhigh { + struct ascelllow* ptr_low; +}; + +typedef struct ascellhigh *ascellhigh_p; + /* Private hook data */ struct ng_netflow_iface { hook_p hook; /* NULL when disconnected */ @@ -451,8 +542,10 @@ u_char flowset_records[NETFLOW_V9_MAX_FLOWSETS - 1]; /* Count of records in each flowset */ uint16_t mtu; /* export interface MTU */ struct netflow_v9_flowset_header *v9_flowsets[NETFLOW_V9_MAX_FLOWSETS - 1]; /* Pointers to pre-compiled flowsets */ - struct ng_netflow_iface ifaces[NG_NETFLOW_MAXIFACES]; + + /* List of Autonomous System */ + struct ascellhigh astable[255][255]; }; typedef struct netflow *priv_p; @@ -473,6 +566,8 @@ #define priv_to_fib(priv, fib) (priv)->fib_data[(fib)] +MALLOC_DECLARE(M_NETFLOW_HASH); + /* * Cisco uses milliseconds for uptime. Bad idea, since it overflows * every 48+ days. But we will do same to keep compatibility. This macro @@ -495,6 +590,9 @@ int ng_netflow_flow_add(priv_p, fib_export_p, struct ip *, caddr_t, uint8_t, uint8_t, unsigned int); int ng_netflow_flow6_add(priv_p, fib_export_p, struct ip6_hdr *, caddr_t , uint8_t, uint8_t, unsigned int); int ng_netflow_flow_show(priv_p, struct ngnf_show_header *req, struct ngnf_show_header *resp); +int AddNetToAS (ascellhigh_p, u_int8_t, u_int8_t, u_int8_t, u_int8_t, u_int8_t, u_int16_t); +u_int16_t GetAsnumber (ascellhigh_p, u_int8_t, u_int8_t, u_int8_t, u_int8_t); + void ng_netflow_v9_cache_init(priv_p); void ng_netflow_v9_cache_flush(priv_p); --- ng_netflow.4.orig 2013-03-26 15:13:36.000000000 +0700 +++ ng_netflow.4 2013-03-26 16:54:31.000000000 +0700 @@ -263,6 +263,34 @@ uint16_t mtu; /* v9 MTU */ }; .Ed +.It Dv NGM_NETFLOW_ADDNETTOAS Pq Ic addnettoas +This control message add information about origin AS of network for filling fields src_as and dst_as in Netflow v5 datagramms. +This message requires +.Vt "struct ng_netflow_addnettoas" +as an argument: +.Bd -literal -offset 4n +struct ng_netflow_addnettoas { + u_int8_t ipoct1; /*first octet of IPV4-network*/ + u_int8_t ipoct2; /*second octet of IPV4-network*/ + u_int8_t ipoct3; /*third octet of IPV4-network*/ + u_int8_t ipoct4; /*fourth octet of IPV4-network*/ + u_int8_t masklen; /*network mask of IPV4-network*/ + u_int16_t asnum; /*origin AS of network*/ +}; +.Ed +.It Dv NGM_NETFLOW_GETASNUMBER Pq Ic getasnumber +This control message returns origin AS of IPV4-address. +This message requires +.Vt "struct ng_netflow_getasnumber" +as an argument: +.Bd -literal -offset 4n +struct ng_netflow_getasnumber { + u_int8_t ipoct1; /*first octet of IPV4-address*/ + u_int8_t ipoct2; /*second octet of IPV4-address*/ + u_int8_t ipoct3; /*third octet of IPV4-address*/ + u_int8_t ipoct4; /*fourth octet of IPV4-address*/ +}; +.Ed .El .Sh SHUTDOWN This node shuts down upon receipt of a @@ -338,6 +366,7 @@ .An Gleb Smirnoff Aq glebius@FreeBSD.org , .An Alexander Motin Aq mav@FreeBSD.org , .An Alexander Chernikov Aq melifaro@ipfw.ru . +.An Stas Timokhin Aq devel@stasyan.com . The initial code was based on .Nm ng_ipacct written by @@ -349,8 +378,4 @@ .Pp The .Nm -node type does not fill in AS numbers. -This is due to the lack of necessary information in the kernel routing table. -However, this information can be injected into the kernel from a routing daemon -such as GNU Zebra. -This functionality may become available in future releases. +node type can fill AS numbers. This requires inject information to node from external sources with message NGM_NETFLOW_ADDNETTOAS