Adding DnsGuard sample App
[toolkit.git] / samples / dnsguard / src / main / java / org / sdnhub / dnsguard / DnsGuard.java
1 package org.sdnhub.dnsguard;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileInputStream;
6 import java.io.FileNotFoundException;
7 import java.io.FileOutputStream;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.io.InputStreamReader;
11 import java.io.OutputStream;
12 import java.io.StringWriter;
13 import java.net.URL;
14 import java.util.ArrayList;
15 import java.util.Enumeration;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.Properties;
19 import java.util.Set;
20
21 import net.dougharris.dns.RFC1035;
22
23 import org.opendaylight.controller.hosttracker.IfHostListener;
24 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
25 import org.opendaylight.controller.sal.action.Action;
26 import org.opendaylight.controller.sal.action.Controller;
27 import org.opendaylight.controller.sal.core.Node;
28 import org.opendaylight.controller.sal.core.NodeConnector;
29 import org.opendaylight.controller.sal.core.Property;
30 import org.opendaylight.controller.sal.core.UpdateType;
31 import org.opendaylight.controller.sal.flowprogrammer.Flow;
32 import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService;
33 import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
34 import org.opendaylight.controller.sal.match.Match;
35 import org.opendaylight.controller.sal.match.MatchField;
36 import org.opendaylight.controller.sal.match.MatchType;
37 import org.opendaylight.controller.sal.packet.Ethernet;
38 import org.opendaylight.controller.sal.packet.IDataPacketService;
39 import org.opendaylight.controller.sal.packet.IListenDataPacket;
40 import org.opendaylight.controller.sal.packet.IPv4;
41 import org.opendaylight.controller.sal.packet.Packet;
42 import org.opendaylight.controller.sal.packet.PacketResult;
43 import org.opendaylight.controller.sal.packet.RawPacket;
44 import org.opendaylight.controller.sal.packet.UDP;
45 import org.opendaylight.controller.sal.utils.EtherTypes;
46 import org.opendaylight.controller.sal.utils.NetUtils;
47 import org.opendaylight.controller.sal.utils.ServiceHelper;
48 import org.opendaylight.controller.sal.utils.Status;
49 import org.opendaylight.controller.switchmanager.ISwitchManager;
50 import org.osgi.framework.BundleContext;
51 import org.osgi.framework.FrameworkUtil;
52 import org.sdnhub.dnsguard.renders.DnsRecordReply;
53 import org.sdnhub.dnsguard.renders.DnsUsage;
54 import org.sdnhub.dnsguard.renders.Violator;
55 //import org.sdnhub.learningswitch.ILearningSwitch;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 public class DnsGuard implements IListenDataPacket, IListenInventoryUpdates,
60                 IfHostListener, IDnsGuard {
61
62         private DnsGuardPersistence database;
63
64         protected static final Logger log = LoggerFactory.getLogger(DnsGuard.class);
65         private String dbconfig_filename = "database.config";
66         
67         private IDataPacketService dataPacketService = null;
68
69         void setDataPacketService(IDataPacketService s) {
70                 this.dataPacketService = s;
71         }
72
73         void unsetDataPacketService(IDataPacketService s) {
74                 if (this.dataPacketService == s) {
75                         this.dataPacketService = null;
76                 }
77         }
78
79         private ISwitchManager swManager = null;
80
81         void setSwitchManager(ISwitchManager s) {
82                 log.info("set ISwitchManager");
83                 this.swManager = s;
84         }
85
86         void unsetSwitchManager(ISwitchManager s) {
87                 if (this.swManager == s) {
88                         this.swManager = null;
89                 }
90         }
91
92         private IFlowProgrammerService programmer = null;
93
94         public void setFlowProgrammerService(IFlowProgrammerService s) {
95                 this.programmer = s;
96         }
97
98         public void unsetFlowProgrammerService(IFlowProgrammerService s) {
99                 if (this.programmer == s) {
100                         this.programmer = null;
101                 }
102         }
103
104         @Override
105         public PacketResult receiveDataPacket(RawPacket inPkt) {
106
107                 // log.info("packet arrived");
108
109                 Packet etherpack = this.dataPacketService.decodeDataPacket(inPkt);
110
111                 if (etherpack instanceof Ethernet) {
112
113                         Packet ippack = etherpack.getPayload();
114
115                         if (ippack instanceof IPv4) {
116
117                                 Packet udppackt = ippack.getPayload();
118
119                                 if (udppackt instanceof UDP) {
120
121                                         // & 0xFFFF
122                                         short sport = ((UDP) udppackt).getSourcePort();
123                                         short dport = ((UDP) udppackt).getDestinationPort();
124
125                                         if (sport == 53 || dport == 53) {
126
127                                                 int sip = ((IPv4) ippack).getSourceAddress();
128                                                 int dip = ((IPv4) ippack).getDestinationAddress();
129
130                                                 byte[] dnspacket = ((UDP) udppackt).getRawPayload();
131
132                                                 if (dnspacket != null) {
133
134                                                         RFC1035 dns_msg = new RFC1035(dnspacket);
135
136                                                         try {
137                                                                 dns_msg.parse();
138
139                                                                 if (dns_msg.qr == false) {
140
141                                                                         log.info(
142                                                                                         "DNS REPLY len: {}  from: {} to: {} dport: {}",
143                                                                                         dnspacket.length, NetUtils
144                                                                                                         .getInetAddress(sip)
145                                                                                                         .toString(), NetUtils
146                                                                                                         .getInetAddress(dip)
147                                                                                                         .toString(), dport);
148
149                                                                         DnsReply reply = new DnsReply(dns_msg);
150
151                                                                         if (dns_msg.getCountAnswer() > 0) {
152                                                                                 reply.setPacketHeaders(NetUtils
153                                                                                                 .getInetAddress(sip).toString()
154                                                                                                 .replace("/", ""), NetUtils
155                                                                                                 .getInetAddress(dip).toString()
156                                                                                                 .replace("/", ""), sport, dport);
157                                                                                 database.save(reply);
158                                                                         }
159                                                                 }
160
161                                                         } catch (Exception ex) {
162
163                                                                 log.error(ex.getLocalizedMessage());
164                                                         }
165                                                 }
166                                         }
167                                 }
168                         }
169                 }
170
171                 return PacketResult.KEEP_PROCESSING;
172         }
173
174         void init() {
175
176 //              ILearningSwitch simple = (ILearningSwitch) ServiceHelper.getInstance(
177 //                              ILearningSwitch.class, "default", this);
178 //              if (simple == null) {
179 //                      log.error("Not able to find the learningswitch");
180 //              } else {
181 //                      log.info("learningswitch found, loaded before dnsguard OK");
182 //              }
183
184                 // read info from config file
185
186                 connectToDb();
187
188         }
189
190         private String getDatabaseSql(){
191                 
192                 BundleContext bundleContext = FrameworkUtil.getBundle( this.getClass()).getBundleContext();
193
194                 URL urlfile = bundleContext.getBundle().getResource("/database.sql"); 
195                 
196                 InputStream input;
197                 
198                 //TODO: LC FIX
199                 String sqlCreation = "";
200                 
201                 try{
202                         
203                         input = urlfile.openConnection().getInputStream();
204                         
205                         BufferedReader br = new BufferedReader(new InputStreamReader(input));
206                         String line;
207                         
208                         while ((line = br.readLine()) != null) {
209                                 sqlCreation = sqlCreation + line;
210                         }
211                         
212                 } catch (IOException e) {
213                         // TODO Auto-generated catch block
214                         e.printStackTrace();
215                 }
216                 
217                 return sqlCreation;
218                 
219         }
220         private void connectToDb(){
221           
222                 String sqlCreation = getDatabaseSql(); 
223                 Properties prop = getStartupConfig(dbconfig_filename);
224                 
225                 // connect to db
226                 database = new DnsGuardPersistence(prop.getProperty("dbserver"),
227                                 Integer.valueOf(prop.getProperty("dbport")),
228                                 prop.getProperty("dbname"), prop.getProperty("dbuser"),
229                                 prop.getProperty("dbpasswd"), Integer.valueOf(prop
230                                                 .getProperty("internal_buffer_init_size")),
231                                 Integer.valueOf(prop.getProperty("internal_buffer_max_size")), sqlCreation);
232                  
233                 
234                 boolean dbconx = database.Connect();
235
236                 log.info("Database connected: {} ", dbconx);
237         }
238
239         /*
240          * This method read from a file shipped with the bundle... 
241          * This method is deprecated, and still in code to have a reference how to read resources
242          */
243 //      public Properties getStartupConfig(String filename) {
244 //
245 //              // http://www.mkyong.com/java/java-properties-file-examples/
246 //
247 //              Properties prop = new Properties();
248 //              InputStream input = null;
249 //
250 //              try {
251 //
252 //                      BundleContext bundleContext = FrameworkUtil.getBundle(
253 //                                      this.getClass()).getBundleContext();
254 //                       
255 //                      URL urlfile = bundleContext.getBundle().getResource(
256 //                                      "/database.config");
257 //
258 //                      // input = new FileInputStream(
259 //                      // bundleContext.getBundle().getResource("database.config").to );
260 //
261 //                      input = urlfile.openConnection().getInputStream();
262 //
263 //                      // load a properties file
264 //                      prop.load(input);
265 //
266 //                      input.close();
267 //                       
268 //                      Enumeration<?> e = prop.propertyNames();
269 //                      while (e.hasMoreElements()) {
270 //                              String key = (String) e.nextElement();
271 //                              String value = prop.getProperty(key);
272 //                              log.info(key + ": " + value);
273 //                      }
274 //                      
275 //                              //LC: This section is for using a file in the local bundle storage (seems only available at running time)
276 //                              File foutput = bundleContext.getDataFile("dns-guard-save.txt");
277 //                              OutputStream  fostream = new FileOutputStream(foutput);
278 //                              
279 //                              Properties newprop = new Properties();
280 //                              newprop.put("newval", "luis");
281 //                              
282 //                              newprop.store(fostream, "");
283 //                              
284 //                              fostream.close();
285 //                      
286 //                      return prop;
287 //
288 //              } catch (IOException ex) {
289 //                      ex.printStackTrace();
290 //              } finally {
291 //                      if (input != null) {
292 //                              try {
293 //                                      input.close();
294 //                              } catch (IOException e) {
295 //                                      e.printStackTrace();
296 //                              }
297 //                      }
298 //              }
299 //
300 //              return null;
301 //
302 //      }
303
304         public Properties getStartupConfig(String filename) {
305
306                 // http://www.mkyong.com/java/java-properties-file-examples/
307
308                 Properties prop = new Properties();
309                 InputStream input = null;
310
311                 try {
312
313                         BundleContext bundleContext = FrameworkUtil.getBundle(
314                                         this.getClass()).getBundleContext();
315                          
316                         File configfile = bundleContext.getDataFile( dbconfig_filename );
317                          
318                         input = new FileInputStream(configfile);
319
320                         // load a properties file
321                         prop.load(input);
322
323                         input.close();
324                         
325                         Enumeration<?> e = prop.propertyNames();
326                         while (e.hasMoreElements()) {
327                                 String key = (String) e.nextElement();
328                                 String value = prop.getProperty(key);
329                                 log.info(key + ": " + value);
330                         }
331                         
332                         return prop;
333
334                 } catch (IOException ex) {
335                         ex.printStackTrace();
336                 } finally {
337                         if (input != null) {
338                                 try {
339                                         input.close();
340                                 } catch (IOException e) {
341                                         e.printStackTrace();
342                                 }
343                         }
344                 }
345
346                 return prop;
347
348         }
349         
350         @Override
351         public String echo(String in) {
352                 return in + " from class";
353         }
354
355         @Override
356         public List<String> lazyresolv(String appIp) {
357
358                 // select distinct request FROM dnsspy.bulkreply where data =
359                 // '61.211.161.1'
360                 if (database.Connect()) {
361                         return database.lazyresolv(appIp);
362                 }
363
364                 return new ArrayList<String>();
365         }
366
367         @Override
368         public List<String> appsbyip(String sourceIp) {
369
370                 // select distinct request FROM dnsspy.bulkreply where data =
371                 // '61.211.161.1'
372                 if (database.Connect()) {
373                         return database.appsbyip(sourceIp);
374                 }
375
376                 return new ArrayList<String>();
377         }
378
379         @Override
380         public void updateNode(Node node, UpdateType type, Set<Property> props) {
381                 // log.info("updateNode, NodeType {} Update {} Prop {}",
382                 // node.getID().toString(), type.toString(), props.toString());
383
384                 if (type == UpdateType.ADDED) {
385
386                         for (Iterator<Property> it = props.iterator(); it.hasNext();) {
387
388                                 Property pval = it.next();
389
390                                 // log.info("updateNode {} - {}", pval.getName().toString(),
391                                 // pval.getStringValue());
392
393                                 if (pval.getName() == "macAddress") {
394
395                                         log.info("sw is up");
396
397                                         // forward dns traffic to controller: TP_DST, (short)53
398                                         Match match = new Match();
399                                         match.setField(new MatchField(MatchType.DL_TYPE,
400                                                         EtherTypes.IPv4.shortValue()));
401                                         match.setField(new MatchField(MatchType.NW_PROTO, (byte) 17));
402                                         match.setField(new MatchField(MatchType.TP_DST, (short) 53));
403
404                                         List<Action> actions = new ArrayList<Action>();
405                                         actions.add(new Controller());
406
407                                         Flow flow = new Flow(match, actions);
408                                         flow.setIdleTimeout((short) 0);
409                                         flow.setHardTimeout((short) 0);
410                                         flow.setPriority((short) 32769);
411
412                                         // Modify the flow on the network node
413                                         Status status = programmer.addFlow(node, flow);
414
415                                         if (!status.isSuccess()) {
416                                                 log.warn(
417                                                                 "SDN Plugin failed to program the flow: {}. The failure is: {}",
418                                                                 flow, status.getDescription());
419                                         }
420
421                                         // forward dns traffic to controller: TP_SRC, (short)53
422                                         // match = new Match();
423                                         // match.setField( new MatchField(MatchType.DL_TYPE,
424                                         // EtherTypes.IPv4.shortValue()));
425                                         // match.setField( new MatchField(MatchType.NW_PROTO,
426                                         // (byte)17) );
427                                         // match.setField( new MatchField(MatchType.TP_SRC,
428                                         // (short)53) );
429                                         //
430                                         // actions = new ArrayList<Action>();
431                                         // actions.add(new Controller());
432                                         //
433                                         // flow = new Flow(match, actions);
434                                         // flow.setIdleTimeout((short) 0);
435                                         // flow.setHardTimeout((short) 0);
436                                         // flow.setPriority( (short) 32769);
437                                         //
438                                         // // Modify the flow on the network node
439                                         // status = programmer.addFlow(node, flow);
440                                         //
441                                         // if (!status.isSuccess()) {
442                                         // log.warn("SDN Plugin failed to program the flow: {}. The failure is: {}",
443                                         // flow, status.getDescription());
444                                         // }
445
446                                         // if(this.swManager != null){
447                                         // Set<NodeConnector> nconx =
448                                         // this.swManager.getNodeConnectors(node);
449                                         // log.info("got nconx");
450                                         // }
451                                 }
452
453                         }
454
455                 }
456
457         }
458
459         @Override
460         public void updateNodeConnector(NodeConnector nodeConnector,
461                         UpdateType type, Set<Property> props) {
462
463         }
464
465         @Override
466         public void hostListener(HostNodeConnector host) {
467                 log.info("new host {}", host.getNetworkAddressAsString());
468         }
469
470         @Override
471         public List<Violator> getViolators() {
472
473                 // select distinct request FROM dnsspy.bulkreply where data =
474                 // '61.211.161.1'
475                 if (database.Connect()) {
476                         return database.getViolators();
477                 }
478
479                 return new ArrayList<>();
480         }
481
482         @Override
483         public String setLocalDnsServer(String local_dns) {
484
485                 // select distinct request FROM dnsspy.bulkreply where data =
486                 // '61.211.161.1'
487                 if (database.Connect()) {
488                         return database.setLocalDnsServer(local_dns);
489                 }
490
491                 return new String("Error updating data");
492         }
493
494         @Override
495         public String getLocalDnsServer() {
496
497                 // select distinct request FROM dnsspy.bulkreply where data =
498                 // '61.211.161.1'
499                 if (database.Connect()) {
500                         return database.getLocalDnsServer();
501                 }
502
503                 return new String("Error getting data");
504         }
505
506         @Override
507         public List<DnsUsage> getExternalDnsUsage(int top) {
508                 // select distinct request FROM dnsspy.bulkreply where data =
509                 // '61.211.161.1'
510                 if (database.Connect()) {
511
512                         return database.getExternalDnsUsage(top);
513                 }
514
515                 return new ArrayList<>();
516         }
517
518         @Override
519         public List<DnsRecordReply>getDatabaseDnsRecords(int limit, int offset) {
520                 // TODO Auto-generated method stub
521                 if (database.Connect()) {
522
523                         return database.getDatabaseDnsRecords(limit, offset);
524                 }
525
526                 return new ArrayList<>();
527         }
528         
529         @Override
530         public Boolean isConnected(){
531                 
532                 if(database != null){
533                         return database.isConnected();
534                 }
535                 
536                 return false;
537         }
538         
539         @Override
540         public void savePropsAndConnect(Properties props){
541                 
542                 BundleContext bundleContext = FrameworkUtil.getBundle(
543                                 this.getClass()).getBundleContext();
544                 
545                 File foutput = bundleContext.getDataFile( dbconfig_filename );
546                 OutputStream fostream;
547                 
548                 try {
549                         fostream = new FileOutputStream(foutput);
550                         
551                          
552                         props.store(fostream, "");
553                         fostream.close();
554                         
555                 } catch ( IOException e) {
556                         // TODO Auto-generated catch block
557                         e.printStackTrace();
558                 }
559  
560                 connectToDb();
561                 
562         }
563         
564 }