/* * Copyright 2011 Future Systems * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.krakenapps.captiveportal.impl; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import org.krakenapps.pcap.decoder.ethernet.EthernetFrame; import org.krakenapps.pcap.decoder.ethernet.MacAddress; import org.krakenapps.pcap.live.PcapDevice; import org.krakenapps.pcap.util.Buffer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FakeDns { private FakeDns() { } public static boolean isDnsPacket(int protocol, int dstPort) { return protocol == 17 && dstPort == 53; } public static void forgeResponse(InetAddress fakeIp, PcapDevice device, EthernetFrame frame, InetAddress src, int srcPort, InetAddress dst, int dstPort, Buffer buf) { if (fakeIp == null || device == null) return; InetSocketAddress source = new InetSocketAddress(src, srcPort); InetSocketAddress destination = new InetSocketAddress(dst, dstPort); FakeDnsResponse r = getDnsResponse(fakeIp, frame, source, destination, buf); if (r != null) sendPacket(device, r.getPacket()); Logger logger = LoggerFactory.getLogger(FakeDns.class.getName()); logger.trace("kraken captive portal: sent fake dns response, " + r); } private static void sendPacket(PcapDevice device, Buffer b) { try { device.write(b); } catch (IOException e) { Logger logger = LoggerFactory.getLogger(FakeDns.class.getName()); logger.error("kraken captive portal: cannot route packet", e); } } private static FakeDnsResponse getDnsResponse(InetAddress fakeIp, EthernetFrame frame, InetSocketAddress src, InetSocketAddress dst, Buffer buf) { buf.rewind(); buf.skip(28); // skip length and checksum int txId = buf.getUnsignedShort(); int flags = buf.getUnsignedShort(); int questionCount = buf.getUnsignedShort(); int answerCount = buf.getUnsignedShort(); int authorityCount = buf.getUnsignedShort(); int additionalCount = buf.getUnsignedShort(); if (flags != 0x0100) return null; boolean isQuery = (questionCount == 1 && answerCount == 0 && authorityCount == 0 && additionalCount == 0); if (!isQuery) return null; String domain = decodeDomain(buf); int type = buf.getUnsignedShort(); int clazz = buf.getUnsignedShort(); if (type != 1 || clazz != 1) return null; MacAddress targetMac = frame.getSource(); return new FakeDnsResponse(targetMac, src, dst, (short) txId, domain, fakeIp); } private static String decodeDomain(Buffer buf) { String domain = ""; while (true) { byte length = buf.get(); if (length == 0) break; byte[] b = new byte[length]; buf.gets(b); String token = new String(b); if (domain.length() == 0) domain += token; else domain += "." + token; } return domain; } }