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