package org.freertr.ip; import org.freertr.addr.addrIP; import org.freertr.addr.addrIPv4; import org.freertr.cfg.cfgAll; import org.freertr.pack.packHolder; import org.freertr.util.debugger; import org.freertr.util.logger; /** * does ipv4 (rfc791) packet handling * * @author matecsaba */ public class ipCor4 implements ipCor { /** * create instance */ public ipCor4() { } /** * size of ipv4 header */ public final static int size = 20; /** * protocol version */ public final static int protocolVersion = 4; /** * protocol nlpid */ public final static int protocolNLPID = 0xcc; /** * protocol number */ public final static int protocolNumber = 4; private static int nextPackIDval = 0; public int getVersion() { return protocolVersion; } public int getProtocol() { return protocolNumber; } public int getNlpid() { return protocolNLPID; } public int getHeaderSize() { return size; } public boolean parseIPheader(packHolder pck, boolean chksiz) { addrIPv4 adr = new addrIPv4(); pck.getAddr(adr, 12); // source address pck.IPsrc.fromIPv4addr(adr); checkAddrSrc(pck, adr); pck.getAddr(adr, 16); // destination address pck.IPtrg.fromIPv4addr(adr); checkAddrTrg(pck, adr); int hdrLen = pck.getByte(0); // version:4 headerLen:4 if ((hdrLen >>> 4) != protocolVersion) { logger.info("got bad version from " + pck.IPsrc); return true; } hdrLen = (hdrLen & 0xf) << 2; if (hdrLen < size) { logger.info("got too small from " + pck.IPsrc); return true; } if (cfgAll.ipv4ChecksumRx) { if (pck.getIPsum(0, hdrLen, 0) != 0xffff) { logger.info("got bad checksum from " + pck.IPsrc); return true; } } int totLen = pck.msbGetW(2); // total Length of this packet (hdr incl) if (hdrLen > totLen) { logger.info("got too small from " + pck.IPsrc); return true; } if (chksiz) { if (totLen > pck.dataSize()) { logger.info("got truncated from " + pck.IPsrc); return true; } pck.setDataSize(totLen); } pck.IPtos = pck.getByte(1); // type of service: dscp:6 unused:2 pck.IPid = pck.msbGetW(4); // identification int flagFrag = pck.msbGetW(6); // res:1 DF:1 MF:1 fragOff:13 pck.IPttl = pck.getByte(8); // time to live pck.IPprt = pck.getByte(9); // protocol // int sum = pck.msbGetW(10); // header checksum pck.IPdf = ((flagFrag & 0x4000) != 0); pck.IPmf = ((flagFrag & 0x2000) != 0); pck.IPfrg = (flagFrag & 0x1fff) << 3; pck.IPsiz = hdrLen; pck.IPver = protocolVersion; if (hdrLen > size) { if (pck.msbGetW(size) == 0x9404) { pck.IPalrt = -2; } } if (debugger.ipCor4traf) { logger.debug("rx " + pck.IPsrc + " -> " + pck.IPtrg + " pr=" + pck.IPprt + " tos=" + pck.IPtos); } return false; } public void createIPheader(packHolder pck) { if (pck.IPttl <= 0) { pck.IPttl = cfgAll.ipv4sendingTTL; } if (pck.IPtos < 0) { pck.IPtos = cfgAll.ipv4sendingTOS; } if (pck.IPid < 0) { pck.IPid = (nextPackIDval++) & 0xffff; } if (debugger.ipCor4traf) { logger.debug("tx " + pck.IPsrc + " -> " + pck.IPtrg + " pr=" + pck.IPprt + " tos=" + pck.IPtos); } pck.IPsiz = size; if (pck.IPalrt != -1) { pck.msbPutD(size, 0x94040000); pck.IPsiz += 4; } pck.putByte(0, 0x40 | (pck.IPsiz >>> 2)); // version:4 ihl:4 pck.putByte(1, pck.IPtos); // type of service pck.msbPutW(2, pck.dataSize() + pck.IPsiz); // total length pck.msbPutW(4, pck.IPid); // identification int i = (pck.IPfrg >>> 3) & 0x1fff; if (pck.IPdf) { i |= 0x4000; } if (pck.IPmf) { i |= 0x2000; } pck.msbPutW(6, i); // res:1 DF:1 MF:1 fragOff:13 pck.putByte(8, pck.IPttl); // time to live pck.putByte(9, pck.IPprt); // protocol pck.msbPutW(10, 0); // header checksum addrIPv4 adr = pck.IPsrc.toIPv4(); pck.putAddr(12, adr); // source address checkAddrSrc(pck, adr); adr = pck.IPtrg.toIPv4(); pck.putAddr(16, adr); // destination address if (cfgAll.ipv4ChecksumTx) { pck.lsbPutW(10, 0xffff - pck.putIPsum(0, pck.IPsiz, 0)); // header checksum } checkAddrTrg(pck, adr); pck.IPver = protocolVersion; pck.IPmf = false; pck.IPfrg = 0; pck.putSkip(pck.IPsiz); pck.merge2beg(); } private static void checkAddrSrc(packHolder pck, addrIPv4 adr) { pck.IPlnk = adr.isLinkLocal(); } private static void checkAddrTrg(packHolder pck, addrIPv4 adr) { pck.IPbrd = adr.isBroadcast(); pck.IPmlt = adr.isMulticast(); pck.IPmlr = adr.isRoutedMcast(); pck.IPlnk |= adr.isLinkLocal(); } public void updateIPheader(packHolder pck, addrIP src, addrIP trg, int prt, int ttl, int tos, int id, int len) { if (debugger.ipCor4traf) { logger.debug("upd src=" + src + " trg=" + trg + " prt=" + prt + " ttl=" + ttl + " tos=" + tos + " len=" + len); } pck.unMergeBytes(pck.IPsiz); pck.putSkip(-pck.IPsiz); if (prt != -1) { pck.putByte(9, prt); // protocol pck.IPprt = prt; } if (ttl == -2) { int i = pck.IPttl - 1; if (i < 0) { i = 0; } ttl = i; } if (ttl != -1) { pck.putByte(8, ttl); // time to live pck.IPttl = ttl; } if (tos != -1) { pck.putByte(1, tos); // type of service: dscp:6 unused:2 pck.IPtos = tos; } if (id != -1) { pck.msbPutW(4, id); // indentification pck.IPid = id; } if (len != -1) { pck.msbPutW(2, len + pck.IPsiz); // total length } if (src != null) { addrIPv4 adr = src.toIPv4(); pck.putAddr(12, adr); // source address pck.IPsrc.setAddr(src); checkAddrSrc(pck, adr); } else { checkAddrSrc(pck, pck.IPsrc.toIPv4()); } if (trg != null) { addrIPv4 adr = trg.toIPv4(); pck.putAddr(16, adr); // destination address pck.IPtrg.setAddr(trg); checkAddrTrg(pck, adr); } else { checkAddrTrg(pck, pck.IPtrg.toIPv4()); } pck.msbPutW(10, 0); // header checksum if (cfgAll.ipv4ChecksumTx) { pck.lsbPutW(10, 0xffff - pck.putIPsum(0, pck.IPsiz, 0)); // header checksum } pck.putSkip(pck.IPsiz); pck.mergeHeader(-1, pck.headSize() - pck.IPsiz); } }