package com.lamoop.competition; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.counter.ICounterStoreService; import net.floodlightcontroller.packet.DNS; import net.floodlightcontroller.packet.DNSAnswer; import net.floodlightcontroller.packet.DNSQuery; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPacket; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.packet.UDP; import net.floodlightcontroller.restserver.IRestApiService; import net.floodlightcontroller.util.OFMessageDamper; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFType; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Splitter; public class Defence implements IOFMessageListener, IFloodlightModule, IDefenceService { protected IFloodlightProviderService floodlightProvider; protected Logger logger; protected IRestApiService restApi; protected List<String> blackList; protected List<String> defenceList; protected String fakeIP = "192.168.1.12"; protected ICounterStoreService counterStore; protected OFMessageDamper messageDamper; protected static int OFMESSAGE_DAMPER_CAPACITY = 10000; // ms. protected static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms boolean enabled; @Override public String getName() { return "defence"; } @Override public boolean isCallbackOrderingPrereq(OFType type, String name) { return false; } @Override public boolean isCallbackOrderingPostreq(OFType type, String name) { return (type.equals(OFType.PACKET_IN) && name.equals("forwarding")); } @Override public List<String> getBlackList() { return blackList; } @Override public Collection<Class<? extends IFloodlightService>> getModuleServices() { Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>(); l.add(IDefenceService.class); return l; } @Override public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>(); m.put(IDefenceService.class, this); return m; } @Override public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>(); l.add(IFloodlightProviderService.class); l.add(IRestApiService.class); return l; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { floodlightProvider = context .getServiceImpl(IFloodlightProviderService.class); logger = LoggerFactory.getLogger(Defence.class); restApi = context.getServiceImpl(IRestApiService.class); counterStore = context.getServiceImpl(ICounterStoreService.class); messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY, EnumSet.of(OFType.FLOW_MOD), OFMESSAGE_DAMPER_TIMEOUT); blackList = new ArrayList<String>(); defenceList = new ArrayList<String>(); enabled = true; } @Override public void startUp(FloodlightModuleContext context) throws FloodlightModuleException { floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); Map<String, String> configOptions = context.getConfigParams(this); String domains = configOptions.get("blackList"); Iterable<String> items = Splitter.on(',').trimResults() .omitEmptyStrings().split(domains); for (String item : items) { blackList.add(item); } domains = configOptions.get("defenceList"); items = Splitter.on(',').trimResults() .omitEmptyStrings().split(domains); for (String item : items) { defenceList.add(item); } } @Override public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { Command result = Command.CONTINUE; switch (msg.getType()) { case PACKET_IN: result = processPacketInMessage(sw, msg, cntx); break; default: break; } return result; } private Command processPacketInMessage(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { if (cntx != null) { Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); IPacket pkt = null; try { pkt = eth.getPayload().getPayload().getPayload(); } catch (Exception e) { logger.info("it is not a dns packet"); } if (pkt instanceof DNS) { return processDNSMessage(sw, msg, cntx); } } return Command.CONTINUE; } private Command processDNSMessage(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { logger.info("process dns packet."); OFPacketIn pi = (OFPacketIn) msg; Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); IPv4 nwPkt = (IPv4) eth.getPayload(); UDP tlPkt = (UDP) nwPkt.getPayload(); DNS pkt = (DNS) tlPkt.getPayload(); List<DNSQuery> querys = pkt.getQuerys(); List<DNSAnswer> answers = new ArrayList<DNSAnswer>(); String domain; InetAddress domainIP = null; for (DNSQuery query : querys) { domain = query.getName(); DNSAnswer answer = new DNSAnswer(); if (domainVerify(domain)) { logger.info("the domain is not verified."); answer.setAddr(fakeIP); answers.add(answer); } else { try { domainIP = InetAddress.getByName(domain); } catch (UnknownHostException e) { logger.error("can not get the ip address of " + domain); } if (domainIP != null) { answer.setAddr(domainIP.getHostAddress()); answers.add(answer); } } } IPacket dns = new DNS().setTid(pkt.getTid()).setFlags((short) 0x8180) .setQuestionCount((short) querys.size()) .setAnswerCount((short) answers.size()) .setQuerys(querys) .setAnswers(answers); IPacket udp = new UDP().setDestinationPort(tlPkt.getSourcePort()) .setSourcePort(tlPkt.getDestinationPort()) .setPayload(dns); IPacket ipv4 = new IPv4().setDiffServ((byte) 0) .setIdentification((short) 3358).setFlags((byte) 0) .setFragmentOffset((short) 0).setTtl((byte) 62) .setProtocol(IPv4.PROTOCOL_UDP) .setSourceAddress(nwPkt.getDestinationAddress()) .setDestinationAddress(nwPkt.getSourceAddress()) .setPayload(udp); IPacket dnsReply = new Ethernet() .setSourceMACAddress(eth.getDestinationMACAddress()) .setDestinationMACAddress(eth.getSourceMACAddress()) .setEtherType(Ethernet.TYPE_IPv4).setVlanID(eth.getVlanID()) .setPriorityCode(eth.getPriorityCode()) .setPayload(ipv4); pushPacket(dnsReply, sw, OFPacketOut.BUFFER_ID_NONE, OFPort.OFPP_NONE.getValue(), pi.getInPort(), cntx, true); return Command.STOP; } public void pushPacket(IPacket packet, IOFSwitch sw, int bufferId, short inPort, short outPort, FloodlightContext cntx, boolean flush) { logger.trace("PacketOut srcSwitch={} inPort={} outPort={}", new Object[] { sw, inPort, outPort }); OFPacketOut po = (OFPacketOut) floodlightProvider.getOFMessageFactory() .getMessage(OFType.PACKET_OUT); // set actions List<OFAction> actions = new ArrayList<OFAction>(); actions.add(new OFActionOutput(outPort, (short) 0xffff)); po.setActions(actions).setActionsLength( (short) OFActionOutput.MINIMUM_LENGTH); short poLength = (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH); // set buffer_id, in_port po.setBufferId(bufferId); po.setInPort(inPort); // set data - only if buffer_id == -1 if (po.getBufferId() == OFPacketOut.BUFFER_ID_NONE) { if (packet == null) { logger.error("BufferId is not set and packet data is null. " + "Cannot send packetOut. " + "srcSwitch={} inPort={} outPort={}", new Object[] { sw, inPort, outPort }); return; } byte[] packetData = packet.serialize(); poLength += packetData.length; po.setPacketData(packetData); } po.setLength(poLength); try { counterStore.updatePktOutFMCounterStoreLocal(sw, po); messageDamper.write(sw, po, cntx, flush); } catch (IOException e) { logger.error("Failure writing packet out", e); } } private boolean domainVerify(String domain){ if(blackList.contains(domain)){ return true; } else{ for(String item:defenceList){ if(StringComparer.compare(domain, item)){ return true; } } } return false; } @Override public String getFakeIP() { return fakeIP; } }