package org.freertr.tab; import java.util.ArrayList; import java.util.List; import org.freertr.addr.addrPrefix; import org.freertr.addr.addrType; import org.freertr.ip.ipCor; import org.freertr.ip.ipIcmp; import org.freertr.pack.packHolder; import org.freertr.prt.prtDccp; import org.freertr.prt.prtGenConn; import org.freertr.prt.prtLudp; import org.freertr.prt.prtSctp; import org.freertr.prt.prtTcp; import org.freertr.prt.prtUdp; import org.freertr.user.userFormat; import org.freertr.util.bits; import org.freertr.util.cmds; import org.freertr.util.debugger; import org.freertr.util.logger; /** * represents one sequenced listing * * @param type of one entry * @param type of one address * @author matecsaba */ public class tabListing, Ta extends addrType> { /** * name of prefix list */ public String listName; /** * my ip handler */ public ipCor myCor; /** * my icmp handler */ public ipIcmp myIcmp; /** * my tcp handler */ protected tabGen entries; /** * creates new listing */ public tabListing() { if (debugger.tabListingEvnt) { logger.debug("create"); } entries = new tabGen(); } /** * get statistics * * @param wht what * @return statistics */ public userFormat getStats(int wht) { String a = ""; String b = ""; if ((wht & 1) != 0) { b += "|2tx"; a += "|byte|pack"; } if ((wht & 2) != 0) { b += "|2rx"; a += "|byte|pack"; } if ((wht & 4) != 0) { b += "|2drop"; a += "|byte|pack"; } userFormat l = new userFormat("|", "seq" + a + "|last|timout|cfg", "1" + b + "|2timers|1"); for (int i = 0; i < entries.size(); i++) { Te ntry = entries.get(i); if (ntry == null) { continue; } a = ""; if ((wht & 0x100) != 0) { a = ntry.action + " "; } l.add(ntry.sequence + ntry.getCounters(wht) + "|" + bits.timePast(ntry.lastMatch) + "|" + bits.timeDump(ntry.timeout / 1000) + "|" + a + ntry); } return l; } /** * copy core handlers * * @param src source */ public void copyCores(tabListing src) { myCor = src.myCor; myIcmp = src.myIcmp; } public String toString() { return listName; } /** * clear all prefixes from list */ public void clear() { if (debugger.tabListingEvnt) { logger.debug("clear"); } entries.clear(); } /** * clear counters */ public void counterClear() { if (debugger.tabListingEvnt) { logger.debug("clear counters"); } for (int i = 0; i < entries.size(); i++) { Te ntry = entries.get(i); if (ntry == null) { continue; } if (ntry.hwCntr != null) { ntry.hwSub = ntry.hwCntr.copyBytes(); } ntry.cntr.clear(); ntry.lastMatch = 0; } } /** * clear aged entries * * @return entries removed */ public int purgeAged() { if (debugger.tabListingEvnt) { logger.debug("purge aged"); } long tim = bits.getTime(); int done = 0; for (int i = entries.size() - 1; i >= 0; i--) { Te ntry = entries.get(i); if (ntry == null) { continue; } if (ntry.timeout < 1) { continue; } if ((tim - ntry.lastMatch) < ntry.timeout) { continue; } entries.del(ntry); done++; } if (done > 0) { reindex(0, 0); } return done; } /** * reindex this list * * @param beg initial number * @param inc increment number */ public void reindex(int beg, int inc) { if (beg < 1) { beg = 10; } if (inc < 1) { inc = 10; } if (debugger.tabListingEvnt) { logger.debug("reindex beg=" + beg + " inc=" + inc); } for (int i = entries.size() - 1; i >= 0; i--) { Te prf = entries.get(i); prf.sequence = beg + (i * inc); } } /** * get next sequence number to give * * @return next sequence number to give */ public int nextseq() { int i = entries.size(); if (i < 1) { return 10; } Te ntry = entries.get(i - 1); if (ntry == null) { return 10; } return ntry.sequence + 10; } /** * add one table entry with preset values * * @param ntry entry to add * @return true if newly added, false if updated existing entry */ public boolean add(Te ntry) { if (debugger.tabListingEvnt) { logger.debug("add " + ntry); } return entries.put(ntry) == null; } /** * delete one table entry * * @param ntry prefix to delete * @return false if deleted, true if not found */ public boolean del(Te ntry) { if (debugger.tabListingEvnt) { logger.debug("del " + ntry); } return entries.del(ntry) == null; } /** * count entries in table * * @return number of entries */ public int size() { return entries.size(); } /** * read table entry * * @param idx sequence number 0..size-1 * @return null if not found, the entry from table if found */ public Te get(int idx) { return entries.get(idx); } /** * merge one list * * resequencing will happen * * @param l list * @param skip last entries to skip */ public void mergeOne(tabListing l, int skip) { if (debugger.tabListingEvnt) { logger.debug("merge " + l.listName); } copyCores(l); listName = "merged from " + l.listName; for (int i = 0; i < (l.size() - skip); i++) { Te ntry = l.get(i); ntry.sequence = nextseq(); entries.put(ntry); } } /** * merge two lists * * resequencing will happen * * @param l1 first * @param l2 second */ public void mergeTwo(tabListing l1, tabListing l2) { if ((l1 == null) && (l2 == null)) { return; } if (l2 == null) { mergeOne(l1, 0); return; } if (l1 == null) { mergeOne(l2, 0); return; } mergeOne(l1, 1); mergeOne(l2, 0); listName = "merged from " + l1.listName + " and " + l2.listName; } /** * dump part of this table * * @param beg beginning to add to lines * @param filter filter mode * @return string showing the table */ public List dump(String beg, int filter) { List l = new ArrayList(); for (int i = 0; i < entries.size(); i++) { Te ntry = entries.get(i); if (ntry == null) { continue; } List res = ntry.usrString(beg, filter); if (res.size() > 1) { res.add(beg + cmds.comment); } l.addAll(res); } return l; } /** * find one entry * * @param ntry entry to find * @return entry, null if not found */ public Te find(Te ntry) { return entries.find(ntry); } /** * find prefix list entry * * @param afi address family * @param asn as number * @param net network to test * @return entry, null if nothing found */ public Te find(int afi, int asn, addrPrefix net) { for (int i = 0; i < entries.size(); i++) { Te ntry = entries.get(i); if (ntry == null) { continue; } if (!ntry.matches(afi, asn, net)) { continue; } ntry.cntr.rx(new packHolder(false, false)); ntry.lastMatch = bits.getTime(); if (ntry.logMatch) { logger.info("list " + listName + " matched at sequence " + ntry.sequence + " on " + net); } return ntry; } return null; } /** * find route table entry * * @param afi address family * @param asn as number * @param net network to test * @return entry, null if nothing found */ public Te find(int afi, int asn, tabRouteEntry net) { for (int i = 0; i < entries.size(); i++) { Te ntry = entries.get(i); if (ntry == null) { continue; } if (!ntry.matches(afi, asn, net)) { continue; } ntry.cntr.rx(new packHolder(false, false)); ntry.lastMatch = bits.getTime(); if (ntry.logMatch) { logger.info("list " + listName + " matched at sequence " + ntry.sequence + " on " + net); } return ntry; } return null; } /** * find packet * * @param pck packet to test * @return entry, null if nothing found */ public Te find(packHolder pck) { for (int i = 0; i < entries.size(); i++) { Te ntry = entries.get(i); if (ntry == null) { continue; } if (!ntry.matches(pck)) { continue; } ntry.cntr.rx(pck); ntry.lastMatch = bits.getTime(); if (ntry.logMatch) { logger.info("list " + listName + " matched at sequence " + ntry.sequence + " on " + pck.ETHsrc + " " + pck.ETHtrg + " " + pck.IPprt + " " + pck.IPsrc + " " + pck.UDPsrc + " -> " + pck.IPtrg + " " + pck.UDPtrg); } return ntry; } return null; } /** * parse one packet * * @param l3 parse layer3 header * @param l4 parse layer4 header * @param chksiz check size * @param pck packet to parse */ public void packParse(boolean l3, boolean l4, boolean chksiz, packHolder pck) { if (l3) { if (myCor.parseIPheader(pck, chksiz)) { return; } } if (l4) { pck.getSkip(pck.IPsiz); tabQos.classifyLayer4(pck); pck.getSkip(-pck.IPsiz); } } /** * update one packet * * @param pck packet to update */ public void packUpdate(packHolder pck) { myCor.updateIPheader(pck, pck.IPsrc, pck.IPtrg, -1, -1, -1, -1, -1); pck.getSkip(pck.IPsiz); switch (pck.IPprt) { case prtTcp.protoNum: prtTcp.updateTCPheader(pck, pck.UDPsrc, pck.UDPtrg, -1, -1, -1); break; case prtUdp.protoNum: prtUdp.updateUDPheader(pck, pck.UDPsrc, pck.UDPtrg); break; case prtLudp.protoNum: prtLudp.updateLUDPheader(pck, pck.UDPsrc, pck.UDPtrg); break; case prtDccp.protoNum: prtDccp.updateDCCPheader(pck, pck.UDPsrc, pck.UDPtrg); break; case prtSctp.protoNum: prtSctp.updateSCTPheader(pck, pck.UDPsrc, pck.UDPtrg); break; default: if (pck.IPprt != myIcmp.getProtoNum()) { break; } myIcmp.updateICMPheader(pck); break; } pck.getSkip(-pck.IPsiz); } /** * test one network against this prefix list * * @param afi address family * @param asn as number * @param net network to test * @return true if permitted, false if denied */ public boolean matches(int afi, int asn, addrPrefix net) { Te ntry = find(afi, asn, net); if (ntry == null) { return false; } return ntry.action == tabListingEntry.actionType.actPermit; } /** * test one network against this prefix list * * @param afi address family * @param asn as number * @param net network to test * @return true if permitted, false if denied */ public boolean matches(int afi, int asn, tabRouteEntry net) { Te ntry = find(afi, asn, net); if (ntry == null) { return false; } return ntry.action == tabListingEntry.actionType.actPermit; } /** * update one entry * * @param afi address family * @param asn as number * @param net network number * @param copy copy before update * @return null if denied, copy otherwise */ public tabRouteEntry update(int afi, int asn, tabRouteEntry net, boolean copy) { Te ntry = find(afi, asn, net); if (ntry == null) { return null; } if (ntry.action != tabListingEntry.actionType.actPermit) { return null; } if (copy) { net = net.copyBytes(tabRoute.addType.ecmp); } ntry.update(afi, asn, net); return net; } /** * test one packet against this access list * * @param l3 set true to parse layer3 header before * @param l4 set true to parse layer4 header before * @param pck packet to test * @return true if permitted, false if denied */ public boolean matches(boolean l3, boolean l4, packHolder pck) { packParse(l3, l4, true, pck); Te ntry = find(pck); if (ntry == null) { return false; } return ntry.action == tabListingEntry.actionType.actPermit; } /** * test one connection against this access list * * @param conn connection to test * @return true if permitted, false if denied */ public boolean matches(prtGenConn conn) { packHolder pck = new packHolder(false, false); pck.UDPsrc = conn.portRem; pck.UDPtrg = conn.portLoc; pck.IPsrc.setAddr(conn.peerAddr.copyBytes()); pck.IPtrg.setAddr(conn.iface.addr); Te ntry = find(pck); if (ntry == null) { return false; } return ntry.action == tabListingEntry.actionType.actPermit; } }