Реализация связки Dlink DGS-3610-26G + DES-1228G(vlan на клиента) на основе схемы Cisco2 + Zyxel ( DGS-3610-26G + DES-1228G )
Материал из BiTel WiKi
Подключение абонентов по схеме "vlan-на-клиента", Это замена стандартной схему Cisco2 + Zyxel ( DGS-3610-26G + DES-1228G ). При этом используется оборудование D-Link - на уровне доступа свитчи DES-1228G, в ядре - DGS-3610-26G. И еще в отличи от стандартной схемы порты берутся ни из редактора шлюза Zyxel, а универсальный со вкладки порты в договоре .
Управление осуществляется по telnet. К сожалению в используемом
оборудовании функционал "ip unnumbered" реализован не так как в
коммутаторах Cisco, поэтому использовать его не получится. Работать
необходимо используя технологию supervlan. В кратце - эта технология
позволяет задавать допустимые IP-адреса для конкретного vlan, при этом
закрепить можно только диапазон состоящий минимум из 2-х адресов. Например:
DGS-3610# configure DGS-3610(config)# vlan 1000 DGS-3610(config-vlan)# subvlan-address-range 192.168.100.10 192.168.100.11 DGS-3610(config-vlan)# end
конфигурация шлюза DGS-3610-26G
user_rule.editor.class=bitel.billing.module.services.ipn.editor.vlan.CiscoVlanContactRuleEditor gate_manager.class=bitel.billing.server.ipn.vlan.CiscoVlanGateWorker use.script=1
Команды шлюза DGS-3610-26G
[DEFAULT] [REMOVE] no vlan {VID} [/REMOVE] [OPEN] vlan {VID} exit vlan 100 subvlan {VID} exit vlan {VID} subvlan-address-range {addr1} {addr2} exit ip access-list extended 101 <LOOP> no deny ip host {A} any no deny ip any host {A} </LOOP> exit [/OPEN] [CLOSE] interface gigabitethernet 0/22 no ip access-group 101 in exit ip access-list extended 101 no permit ip any any <LOOP> deny ip host {A} any deny ip any host {A} </LOOP> permit ip any any exit interface gigabitethernet 0/22 ip access-group 101 in exit [/CLOSE] [/DEFAULT]
скрпит шлюза DGS-3610-26G
import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.StringTokenizer; import bitel.billing.common.module.ipn.IPNContractStatus; import bitel.billing.server.ipn.GateWorker; import bitel.billing.server.ipn.UserStatus; import bitel.billing.server.ipn.bean.*; import bitel.billing.server.util.DefaultServerSetup; import bitel.billing.server.util.Utils; import bitel.billing.server.util.telnet.OperationTimedoutException; import bitel.billing.server.util.telnet.TelnetSession; import ru.bitel.bgbilling.common.DefaultSetup; import bitel.billing.common.IPUtils; import bitel.billing.server.util.Utils; import bitel.billing.server.util.telnet.OperationTimedoutException; import bitel.billing.server.util.telnet.TelnetSession; import ru.bitel.bgbilling.modules.ipn.common.bean.*; import bitel.billing.server.util.telnet.ansi.TelnetAnsiSession; //includeBGBS( "bgbs://ru.bitel.bgbilling.kernel.script.common.bean.ScriptLibrary/manad" ); protected void doSync() { log.info( "start of cisco........................................................"); host = gate.getHost(); port = gate.getPort(); DefaultServerSetup gateSetup = new DefaultServerSetup( gate.getConfig(), "\r\n" ); pswd = gate.getKeyword(); login = gateSetup.getStringValue( "login"); timeout = gateSetup.getIntValue( "timeout", 0 ); result = new StringBuffer(); if( log.isDebugEnabled() ) { log.debug( gate.getId() + " gate: " + host + ":" + port + " login: " + login + " passwd: " + pswd ); } log.debug("before connect"); session = new TelnetAnsiSession( host, port); session.setTimeout( timeout ); session.setLoginPromptSequence( ":" ); result.append( session.connect() ); log.debug("after connect"); result.append( session.doCommand( login ) ); log.debug("after login"); session.setLoginPromptSequence( "#" ); result.append( session.doCommand( pswd ) ); log.debug("after pswd"); result.append( session.doCommand( "terminal length 0" ) ); result.append( session.doCommand( "terminal width 0" ) ); log.debug("after terminal"); result.append( session.doCommand( "configure terminal" ) ); log.debug( "execute commands" ); doCommands( session, result, gateSetup ); result.append( session.doCommand( "exit" ) ); result.append( session.doCommand( "write memory" ) ); session.doCommandAsync( "exit" ); log.info("!!!!!!!!!!!start of log!!!!!!!!!!!!!!!!!!!!!"); log.info( result ); log.info("!!!!!!!!!!!!!!! end of log !!!!!!!!!!!!!!!!!"); log.debug( "ok" ); log.info( "end of cisco........................................................"); } protected void add() { } private void doCommands( session, result, gateSetup) throws IOException, OperationTimedoutException { acl = gateSetup.getStringValue( "acl"); vlanResult = getVlanResult( session ); log.info( "!!!!!!!!!!!!!!!!!!!!!!!!!!vlanResult!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" ); log.info( vlanResult ); log.info( "!!!!!!!!!!!!!!!!!!!!!!!!!!vlanResult!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" ); aclResult = getAclResult( session, acl ); log.info( "!!!!!!!!!!!!!!!!!!!!!!!!!!aclResult!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" ); log.info( aclResult ); log.info( "!!!!!!!!!!!!!!!!!!!!!!!!!! end aclResult!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" ); for( UserStatus status : statusList ) { VlanManager manager = new VlanManager(status.mid, con); gateId = gate.getId(); //log.info("gateId=" + gateId); vid = manager.getVlan( gateId, status.contractId ); //log.info("vid=" + vid); log.debug( "status=" + status.status); String addr1 = null; String addr2 = null; date = new GregorianCalendar(); AddressRangeManager man = new AddressRangeManager( con, mid ); addressList = man.getContractAddressRange( status.contractId , date, -1 ); if ( addressList.size() > 0 ) { AddressRange range = addressList.get(0); addr1 = IPUtils.convertIpToString( range.getAddr1() ); addr2 = IPUtils.convertIpToString( range.getAddr2() ); } else { log.info( "empty adress on cid = " + status.contractId ); continue; } rules = null; if (status.status == IPNContractStatus.STATUS_OPEN && (!vlanExists(vid, vlanResult) || isUserDenied( addr1, addr2, aclResult) ) ) { rules = getOpenRules( status, vid, gateSetup, addr1, addr2, acl ); } else if (status.status == IPNContractStatus.STATUS_REMOVED && ( vlanExists(vid, vlanResult) || isUserDenied( addr1, addr2,aclResult) ) ) { rules = getRemoveRules( status, vid, gateSetup, addr1, addr2, acl ); } //if closed and etc else if ( status.status != IPNContractStatus.STATUS_OPEN && status.status != IPNContractStatus.STATUS_REMOVED && !isUserDenied( addr1, addr2, aclResult) ) { rules = getCloseRules( status, vid, gateSetup, addr1, addr2, acl ); } if (vid > 0 && rules != null ) { for ( String rule : rules ) { //log.debug ("command=" + rule ); result.append( session.doCommand( rule ) ); } } } } getOpenRules( status, vid, gateSetup, addr1, addr2, acl ) { log.debug( "geting open rules..."); return getRules( status, "\\[OPEN\\](.*)\\[/OPEN\\]", vid, gateSetup, addr1, addr2, acl ); } getCloseRules( status, vid, gateSetup, addr1, addr2, acl ) { log.debug( "geting close rules..."); return getRules( status, "\\[CLOSE\\](.*)\\[/CLOSE\\]", vid, gateSetup, addr1, addr2, acl ); } getRemoveRules( UserStatus status, vid, gateSetup, addr1, addr2, acl ) { log.debug( "geting remove rules..."); return getRules( status, "\\[REMOVE\\](.*)\\[/REMOVE\\]", vid, gateSetup, addr1, addr2, acl ); } getRules( status, template, vid, gateSetup, addr1, addr2, acl ) { // пользовательское правило, без типа - то все оставляем как есть CiscoRule ciscoRule = new CiscoRule ( status.rule.getRuleText() ); rule = ciscoRule.getAddresses(); //log.info("rule=" + rule); //типизированное правило if( status.ruleType != null ) { rule = generateRule( rule, status.gateType, status.ruleType, vid, status.contractId, gateSetup, addr1, addr2, acl ); } //log.info("rule=" + rule); pattern = Pattern.compile( template, Pattern.DOTALL ); m = pattern.matcher( rule ); if (m.find()) { rule = m.group( 1 ); } rule.replaceAll( "\r", "" ); parts = rule.split( "\n" ); result = new ArrayList(); for ( String part : parts ) { if ( !Utils.isEmptyString( part )) { result.add( part ); } } return result; } generateRule( addresses, gateType, ruleType, int vid, int cid, gateSetup, addr1, addr2, acl ) { supervlan = gateSetup.getIntValue( "supervlan", 0 ); Map replacements = new HashMap(); if ( addr1 != null && addr2 != null ) { replacements.put( "\\{addr1\\}", addr1 ); replacements.put( "\\{addr2\\}", addr2 ); replacements.put( "\\{SUPERVLAN\\}", String.valueOf( supervlan) ); replacements.put( "\\{ACL\\}", acl ); } ruleText = ManadUtils.getRule( gateType, ruleType ); if ( vid > 0) { replacements.put( "\\{VID\\}", String.valueOf( vid ) ); } return ManadUtils.generateRule( ruleText, addresses, replacements, ruleType ); } private isUserDenied ( addr1, addr2, buffer) { //эскейпируем точки в адресе String address1 = addr1.replace( ".", "\\." ); String address2 = addr2.replace( ".", "\\." ); return isUserDeniedForAddress( address1, buffer ) && isUserDeniedForAddress( address2, buffer ); } private isUserDeniedForAddress ( address, buffer) { //эскейпируем точки в адресе //String address = addr1.replace( ".", "\\." ); //log.debug( "aaddr1=" + address ); String template = ".*deny ip host\\s+" + address + "\\s+any.*$"; //log.debug( "template=" + template ); Pattern pattern = Pattern.compile( template, Pattern.DOTALL ); Matcher m = pattern.matcher( buffer ); boolean found = m.find(); if ( found ) { log.debug( "user2 denied" ); return true; } pattern = Pattern.compile( ".*deny ip any host\\s" + address + "\\s.*$", Pattern.DOTALL ); m = pattern.matcher( buffer ); found = m.find(); log.debug( found ? "user denied" :"user not denied" ); return found; } private vlanExists ( vlan, buffer) { Pattern pattern = Pattern.compile( ".*" + vlan + "\\s+ON\\s+.*", Pattern.DOTALL ); Matcher m = pattern.matcher( buffer ); found = m.find(); log.debug( found ? "vlan found" : "vlan not found" ); return found; } private getVlanResult( session ) { return session.doCommand( "show supervlan"); } private getAclResult( session, acl ) { return session.doCommand( "show access-lists " + acl ); }
конфигурация шлюза Доступа Dlink
user_rule.editor.class=bitel.billing.module.services.ipn.editor.vlan.CiscoSSHSwitchRuleEditor gate_manager.class=bitel.billing.server.ipn.vlan.CiscoSSHSwitchGateWorker use.script=1
Команды шлюза доступа
[DEFAULT] [OPEN] create vlan vlan{VID} tag {VID} config vlan vlan{VID} add tagged {UPLINK_PORT} <LOOP_PORT> config vlan vlan{VID} add untagged {PORT} config ports {PORT} description {CONTRACT_NAME} </LOOP_PORT> save config [/OPEN] [CLOSE] [/CLOSE] [REMOVE] delete vlan vlan{VID} <LOOP_PORT> config ports {PORT} clear_description </LOOP_PORT> save config [/REMOVE] [/DEFAULT]
Скрипт шлюза доступа
import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; import bitel.billing.common.IPUtils; import bitel.billing.common.module.ipn.IPNContractStatus; import bitel.billing.server.ipn.UserStatus; import bitel.billing.server.ipn.dlink.UserPortStatus; import bitel.billing.server.util.DefaultServerSetup; import bitel.billing.server.util.Utils; import bitel.billing.server.util.telnet.OperationTimedoutException; import bitel.billing.server.util.telnet.TelnetSession; import bitel.billing.server.ipn.bean.*; import bitel.billing.server.contract.bean.*; import bitel.billing.server.util.telnet.ansi.TelnetAnsiSession; import ru.bitel.bgbilling.modules.ipn.server.bean.GatePortManager; protected void doSync() { String host = gate.getHost(); int port = gate.getPort(); DefaultServerSetup gateSetup = new DefaultServerSetup( gate.getConfig(), "\r\n" ); String pswd = gate.getKeyword(); String login = gateSetup.getStringValue( "login"); StringBuffer result = new StringBuffer(); if( log.isDebugEnabled() ) { log.debug( gate.getId() + " gate: " + host + ":" + port + " login: " + login + " pswd: " + pswd ); } TelnetAnsiSession session = new TelnetAnsiSession( host, port); session.setLoginPromptSequence( "UserName:" ); log.debug( "before connect" ); result.append( session.connect() ); log.debug( "after connect" ); session.setLoginPromptSequence( ":" ); result.append( session.doCommand( login ) ); log.debug( "after command" ); session.setLoginPromptSequence( "#" ); result.append( session.doCommand( pswd ) ); log.debug( "before pswd" ); log.debug( "execute commands" ); doCommands( session, result, gateSetup); session.setLoginPromptSequence( "****" ); result.append( session.doCommand( "logout" ) ); log.info( "!!!!!!!!!!!!!!!!!!!!!!!!!!! Dlink 3028 !!!!!!!!!!!!!!!!!!!!!!!!!!!!" ); log.info( result.toString() ); log.info( "!!!!!!!!!!!!!!!!!!!!!!!!!!! end of Dlink 3028 !!!!!!!!!!!!!!!!!!!!!!!!!!!!" ); log.debug( "ok" ); } private void doCommands( session, result, DefaultServerSetup gateSetup ) throws IOException, OperationTimedoutException { VlanManager manager = new VlanManager(mid, con); ContractManager cm = new ContractManager( con ); StringBuilder resultCheck = new StringBuilder(); session.setLoginPromptSequence( "All" ); resultCheck.append( session.doCommand("show vlan ports 1-28" ) ); session.setLoginPromptSequence( "#" ); resultCheck.append( session.doCommand("all" ) ); Map vlanPortMap = readPortVlanMap( resultCheck.toString() ); log.debug("!!!!!!!!vlan-port check!!!!!!!!!!!!"); for ( entry : vlanPortMap.entrySet() ) { log.debug("port " + entry.getKey() ); for ( s : entry.getValue() ) { log.debug("vlan " + s ); } } log.debug( "!!!!!!!!end vlan-port check!!!!!!!!!!!!" ); for( UserStatus status : statusList ) { String addrs = null; int port = -1 ; List ports = new GatePortManager( con, mid ).getGatePorts( status.contractId, gate.getId() ); //типизированное правило if( status.ruleType != null ) { rule = status.rule.getRuleText(); addrs = getAddresses( rule ); if ( ports.size() > 0 ) { port = ports.get(0); log.debug( "port=" + port ); } } //берем vlan у родительской циски int vid = manager.getVlan( gate.getParentId(), status.contractId ); //провереям только один порт Set vlans = vlanPortMap.get( port ); boolean exists = vlans != null && vlans.contains( vid ); log.debug( "exists=" + exists ); String[] rules = new String[0]; Contract c = cm.getContractByID( status.contractId ); String title = c.getTitle(); if ( status.status == IPNContractStatus.STATUS_OPEN && !exists ) { rules = getOpenRules( status, vid, title, gateSetup, addrs, ports ); } else if ( status.status == IPNContractStatus.STATUS_REMOVED && exists ) { rules = getRemoveRules( status, vid, title, gateSetup, addrs, ports ); } //close and etc..пока плевать. т.к они все равно пустые else { rules = getCloseRules( status, vid, title, gateSetup, addrs, ports ); } for ( String rule : rules ) { log.debug( "command=" + rule ); result.append( session.doCommand( rule ) ); } } } private String[] getOpenRules( UserStatus status, int vid, title, gateSetup, addrs, ports ) { return getRules( status, "\\[OPEN\\](.*)\\[/OPEN\\]", vid, title, gateSetup, addrs, ports ); } private String[] getCloseRules( UserStatus status, int vid, title, gateSetup, addrs, ports ) { return getRules( status, "\\[CLOSE\\](.*)\\[/CLOSE\\]", vid, title, gateSetup, addrs, ports ); } private String[] getRemoveRules( UserStatus status, int vid, title, gateSetup, addrs, ports ) { return getRules( status, "\\[REMOVE\\](.*)\\[/REMOVE\\]", vid, title, gateSetup, addrs, ports); } getRules( status, template, vid, title, gateSetup, addrs, ports ) { // пользовательское правило, без типа - то все оставляем как есть rule = status.rule.getRuleText(); //типизированное правило if( status.ruleType != null ) { rule = generateRule( addrs, ports, vid, status.gateType, status.ruleType, title, gateSetup ); } pattern = Pattern.compile( template, Pattern.DOTALL ); m = pattern.matcher( rule ); if (m.find()) { rule = m.group( 1 ); } rule.replaceAll( "\r", "" ); parts = rule.split( "\n" ); return parts; } generateRule( addreses, ports, vid, gateType, ruleType, title, gateSetup ) { ruleText = ManadUtils.getRule( gateType, ruleType ); replacements = new HashMap(); if ( vid > 0) { replacements.put( "\\{VID\\}", String.valueOf( vid ) ); } uplink = gateSetup.getIntValue( "uplink.port", 0 ); replacements.put( "\\{UPLINK_PORT\\}", String.valueOf( uplink ) ); replacements.put( "\\{CONTRACT_NAME\\}", title ); loops = ManadUtils.getAddresLoops( addreses ); String [] portArray = new String[ports.size()]; for ( int i = 0; i < ports.size(); i++ ) { portArray[i] = String.valueOf( ports.get(i) ); } //адреса p = new LoopPattern(); p.setLoopPatern( "LOOP_PORT" ); p.setReplace( "\\{PORT\\}" ); p.setObjects( portArray ); loops.add( p ); return ManadUtils.generateRule( ruleText, replacements, ruleType, loops ); } String getAddresses( rule ) { Map result = new HashMap(); //порты идут до #, а адреса идут после String [] parts = rule.split( "#" ); addresesStr = ""; if ( parts.length > 1 ) { addresesStr = parts[1]; } /* portsStr = ""; if ( parts.length > 0 ) { portsStr = parts[0]; } portList = new ArrayList(); parts = portsStr.split( ";" ); for (String part : parts ) { parts2 = part.split( ":" ); if ( parts2.length < 2) { continue; } port = parts2 [1]; portList.add( port ); } String [] ports_ = new String [portList.size()]; for (int i = 0; i < ports_.length; i++) { ports_[i] = portList.get( i ); } result.put( "ports", ports_); result.put( "addrs", addresesStr); */ return addresesStr; } readPortVlanMap( String data ) { Map result = new HashMap(); String [] lines = data.split( "\n" ); String templatePort = ".*?Port\\s(\\d+).*?$"; Pattern patternPort = Pattern.compile( templatePort, Pattern.DOTALL ); Matcher m = patternPort.matcher( data ); String templateVlan = ".*?(\\d+)\\s+X.*?$"; Pattern patternVlan = Pattern.compile( templateVlan, Pattern.DOTALL ); int port = 1; for ( String line : lines ) { m = patternPort.matcher( line ); if ( m.find() ) { port = Integer.valueOf( m.group( 1 ) ); continue; } m = patternVlan.matcher( line ); if ( m.find() ) { int vlan = Integer.valueOf( m.group( 1 ) ); Set vlans = result.get( port ); if ( vlans == null ) { vlans = new HashSet(); result.put( port, vlans ); } vlans.add( vlan ); } //2 - X } return result; }