11package org .graylog .plugins .netflow .v9 ;
22
3- import com .google .common .base .Splitter ;
3+ import com .fasterxml .jackson .databind .JsonNode ;
4+ import com .fasterxml .jackson .databind .ObjectMapper ;
5+ import com .fasterxml .jackson .dataformat .yaml .YAMLFactory ;
46import com .google .common .collect .ImmutableMap ;
57import com .google .common .io .Resources ;
8+ import org .slf4j .Logger ;
9+ import org .slf4j .LoggerFactory ;
610
711import java .io .IOException ;
8- import java .io .UncheckedIOException ;
12+ import java .io .InputStream ;
913import java .net .URL ;
10- import java .nio .charset .StandardCharsets ;
11- import java .util .List ;
14+ import java .util .Iterator ;
1215import java .util .Map ;
1316
1417public class NetFlowV9FieldTypeRegistry {
18+ private static final Logger LOG = LoggerFactory .getLogger (NetFlowV9FieldTypeRegistry .class );
19+ private static final String DEFAULT_DEFINITIONS = "/netflow9.yml" ;
20+
1521 private final Map <Integer , NetFlowV9FieldType > fieldTypes ;
1622
17- public NetFlowV9FieldTypeRegistry () {
18- final URL url = Resources .getResource (this .getClass (), "/netflow9.csv" );
19- final List <String > lines ;
23+ private NetFlowV9FieldTypeRegistry (InputStream definitions ) throws IOException {
24+ this (definitions , new ObjectMapper (new YAMLFactory ()));
25+ }
26+
27+ private NetFlowV9FieldTypeRegistry (InputStream definitions , ObjectMapper yamlMapper ) throws IOException {
2028 try {
21- lines = Resources .readLines (url , StandardCharsets .UTF_8 );
22- } catch (IOException e ) {
23- throw new UncheckedIOException (e );
29+ this .fieldTypes = parseYaml (definitions , yamlMapper );
30+ } catch (Exception e ) {
31+ throw new IllegalArgumentException ("Unable to parse NetFlow 9 definitions" , e );
32+ }
33+ }
34+
35+ public static NetFlowV9FieldTypeRegistry create () throws IOException {
36+ final URL url = Resources .getResource (NetFlowV9FieldTypeRegistry .class , DEFAULT_DEFINITIONS );
37+ try (InputStream inputStream = url .openStream ()) {
38+ return new NetFlowV9FieldTypeRegistry (inputStream );
39+ }
40+ }
41+
42+ public static NetFlowV9FieldTypeRegistry create (InputStream definitions ) throws IOException {
43+ return new NetFlowV9FieldTypeRegistry (definitions );
44+ }
45+
46+ private static Map <Integer , NetFlowV9FieldType > parseYaml (InputStream inputStream , ObjectMapper yamlMapper ) throws IOException {
47+ final JsonNode node = yamlMapper .readValue (inputStream , JsonNode .class );
48+ final ImmutableMap .Builder <Integer , NetFlowV9FieldType > mapBuilder = ImmutableMap .builder ();
49+ final Iterator <Map .Entry <String , JsonNode >> fields = node .fields ();
50+ while (fields .hasNext ()) {
51+ final Map .Entry <String , JsonNode > field = fields .next ();
52+
53+ final Integer id ;
54+ try {
55+ id = Integer .parseInt (field .getKey ());
56+ } catch (NumberFormatException e ) {
57+ LOG .debug ("Skipping record with invalid id: {}" , field .getKey (), e );
58+ continue ;
59+ }
60+
61+ final JsonNode value = field .getValue ();
62+
63+ if (!value .isArray ()) {
64+ LOG .debug ("Skipping invalid record: {}" , field );
65+ continue ;
66+ }
67+
68+ if (value .size () == 1 && ":skip" .equals (value .get (0 ).asText ())) {
69+ LOG .debug ("Skipping record: {}" , field );
70+ continue ;
71+ }
72+
73+ if (value .size () != 2 ) {
74+ LOG .debug ("Skipping incomplete record: {}" , field );
75+ continue ;
76+ }
77+
78+ final JsonNode typeNode = value .get (0 );
79+ final NetFlowV9FieldType .ValueType type ;
80+ if (typeNode .isTextual ()) {
81+ type = symbolToValueType (typeNode .asText ());
82+ } else if (typeNode .isInt ()) {
83+ type = intToValueType (typeNode .asInt ());
84+ } else {
85+ LOG .debug ("Skipping invalid record type: {}" , field );
86+ continue ;
87+ }
88+
89+ final JsonNode nameNode = value .get (1 );
90+ if (!nameNode .isTextual ()) {
91+ LOG .debug ("Skipping invalid record type: {}" , field );
92+ continue ;
93+ }
94+
95+ final String symbol = nameNode .asText ();
96+ final String name = rubySymbolToString (symbol );
97+
98+ mapBuilder .put (id , NetFlowV9FieldType .create (id , type , name ));
99+ }
100+
101+ return mapBuilder .build ();
102+ }
103+
104+ private static String rubySymbolToString (String symbol ) {
105+ if (symbol .charAt (0 ) == ':' ) {
106+ return symbol .substring (1 );
107+ } else {
108+ return symbol ;
24109 }
110+ }
25111
26- final Splitter splitter = Splitter .on (',' ).trimResults ().omitEmptyStrings ();
27- final ImmutableMap .Builder <Integer , NetFlowV9FieldType > fieldTypesBuilder = ImmutableMap .builder ();
28- for (String line : lines ) {
29- final List <String > items = splitter .splitToList (line );
30- final int id = Integer .parseInt (items .get (0 ));
31- final String name = items .get (1 );
32- final NetFlowV9FieldType .ValueType type = NetFlowV9FieldType .ValueType .valueOf (items .get (2 ));
112+ private static NetFlowV9FieldType .ValueType symbolToValueType (String type ) {
113+ switch (type ) {
114+ case ":int8" :
115+ return NetFlowV9FieldType .ValueType .INT8 ;
116+ case ":uint8" :
117+ return NetFlowV9FieldType .ValueType .UINT8 ;
118+ case ":int16" :
119+ return NetFlowV9FieldType .ValueType .INT16 ;
120+ case ":uint16" :
121+ return NetFlowV9FieldType .ValueType .UINT16 ;
122+ case ":int24" :
123+ return NetFlowV9FieldType .ValueType .INT24 ;
124+ case ":uint24" :
125+ return NetFlowV9FieldType .ValueType .UINT24 ;
126+ case ":int32" :
127+ return NetFlowV9FieldType .ValueType .INT32 ;
128+ case ":uint32" :
129+ return NetFlowV9FieldType .ValueType .UINT32 ;
130+ case ":int64" :
131+ return NetFlowV9FieldType .ValueType .INT64 ;
132+ case ":uint64" :
133+ return NetFlowV9FieldType .ValueType .UINT64 ;
134+ case ":ip4_addr" :
135+ return NetFlowV9FieldType .ValueType .IPV4 ;
136+ case ":ip6_addr" :
137+ return NetFlowV9FieldType .ValueType .IPV6 ;
138+ case ":mac_addr" :
139+ return NetFlowV9FieldType .ValueType .MAC ;
140+ case ":string" :
141+ return NetFlowV9FieldType .ValueType .STRING ;
142+ // HACK: http://www.cisco.com/en/US/technologies/tk648/tk362/technologies_white_paper09186a00800a3db9.html#wp9000935
143+ case ":forwarding_status" :
144+ return NetFlowV9FieldType .ValueType .UINT8 ;
145+ // HACK: http://www.cisco.com/en/US/technologies/tk648/tk362/technologies_white_paper09186a00800a3db9.html#wp9000991
146+ case ":application_id" :
147+ return NetFlowV9FieldType .ValueType .VARINT ;
148+ // HACK: http://www.cisco.com/c/en/us/td/docs/security/asa/special/netflow/guide/asa_netflow.html#pgfId-1331620
149+ case ":acl_id_asa" :
150+ return NetFlowV9FieldType .ValueType .VARINT ;
151+ // HACK: https://www.iana.org/assignments/ipfix/ipfix.xml
152+ case "mpls_label_stack_octets" :
153+ return NetFlowV9FieldType .ValueType .UINT32 ;
154+ default :
155+ LOG .debug ("Unknown type: {}" , type );
156+ return NetFlowV9FieldType .ValueType .STRING ;
157+ }
158+ }
33159
34- fieldTypesBuilder .put (id , NetFlowV9FieldType .create (id , type , name ));
160+ private static NetFlowV9FieldType .ValueType intToValueType (int length ) {
161+ switch (length ) {
162+ case 1 :
163+ return NetFlowV9FieldType .ValueType .UINT8 ;
164+ case 2 :
165+ return NetFlowV9FieldType .ValueType .UINT16 ;
166+ case 3 :
167+ return NetFlowV9FieldType .ValueType .UINT24 ;
168+ case 4 :
169+ return NetFlowV9FieldType .ValueType .UINT32 ;
170+ case 8 :
171+ return NetFlowV9FieldType .ValueType .UINT64 ;
172+ default :
173+ LOG .debug ("Unknown type length: " + length );
174+ return NetFlowV9FieldType .ValueType .STRING ;
35175 }
36- this .fieldTypes = fieldTypesBuilder .build ();
37176 }
38177
39178 public NetFlowV9FieldType get (int id ) {
@@ -43,4 +182,5 @@ public NetFlowV9FieldType get(int id) {
43182 public Map <Integer , NetFlowV9FieldType > asMap () {
44183 return fieldTypes ;
45184 }
185+
46186}
0 commit comments