Модифицированный скриптовый шлюз для DES-3526 и подобных
Материал из BiTel WiKi
(Различия между версиями)
Msh (Обсуждение | вклад) (→Задача) |
Msh (Обсуждение | вклад) (→Недостатки и недоделки) |
||
(6 промежуточных версий не показаны.) | |||
Строка 4: | Строка 4: | ||
При разработке данного скрита решались следующие задачи: <br /> | При разработке данного скрита решались следующие задачи: <br /> | ||
- | + | # уменьшение объема скрипта за счет унификации кода, выполняемого при разных командах (открытие, закрытие, удаление);<br /> | |
- | + | # разделение кода скрипта и правил для коммутатора;<br /> | |
- | + | # возможность добавления нескольких IP-адресов на один порт. | |
== Недостатки и недоделки == | == Недостатки и недоделки == | ||
- | + | #правила для коммутатора вводятся все-таки в текст скрипта, а не в конфигурацию шлюза<br /> | |
- | + | #нельзя прописать один порт для разных договоров<br /> | |
- | + | #все манипуляции с IP-адресами договора надо проводить при состоянии его шлюза в положении удален (иначе некоторые записи в коммутаторе останутся до его перезагрузки)<br /> | |
- | + | #подключение к свитчу занимает 5 секунд (наверное это уже проблема в в биллинге - возможно он лезет к DNS)<br /> | |
- | + | #скрипт не проверяет текущее состояние коммутатора, а каждый раз загружает в него нужные команды<br /> | |
- | + | #в боевом режиме оно еще не проверялось <br /> | |
- | + | #не проверялось работа с ipn_dhcp (option82) - предполагается что при одном адресе на порт клиент будет автоматически получать IP, а при нескольких адресах (а это не является массовой услугой) прописывать адреса вручную<br /> | |
== Предварительная настройка коммутатора == | == Предварительная настройка коммутатора == | ||
Строка 23: | Строка 23: | ||
create access_profile packet_content_mask offset_0-15 0x0 0x0 0x0 0x0 offset_16-31 0xFFFF0000 0x0 0xFFFF0000 0x0 offset_32-47 0xFFFFFFFF 0x0 0x0 0x0 profile_id 20 | create access_profile packet_content_mask offset_0-15 0x0 0x0 0x0 0x0 offset_16-31 0xFFFF0000 0x0 0xFFFF0000 0x0 offset_32-47 0xFFFFFFFF 0x0 0x0 0x0 profile_id 20 | ||
- | #блокировка dhcp ответов и разрешение dhcp запросов (они могут отправляться не с адреса пользователя) | + | #блокировка dhcp ответов и разрешение dhcp запросов (они могут отправляться не с IP-адреса пользователя) |
create access_profile ip udp dst_port_mask 0xFFFF profile_id 30 | create access_profile ip udp dst_port_mask 0xFFFF profile_id 30 | ||
config access_profile profile_id 30 add access_id 1 ip udp dst_port 68 port 1 deny | config access_profile profile_id 30 add access_id 1 ip udp dst_port 68 port 1 deny | ||
Строка 39: | Строка 39: | ||
#разрешение arp-запросов | #разрешение arp-запросов | ||
+ | create access_profile packet_content_mask offset_0-15 0x0 0x0 0x0 0x0 offset_16-31 0xFFFF0000 0x0 0xFFFF0000 0x0 profile_id 60 | ||
+ | config access_profile profile_id 60 add access_id 1 packet_content_mask offset_0-15 0x0 0x0 0x0 0x0 offset_16-31 0x8060000 0x0 0x10000 0x0 port 1 permit | ||
+ | .... | ||
+ | config access_profile profile_id 60 add access_id 24 packet_content_mask offset_0-15 0x0 0x0 0x0 0x0 offset_16-31 0x8060000 0x0 0x10000 0x0 port 24 permit | ||
+ | |||
Строка 47: | Строка 52: | ||
</source> | </source> | ||
- | коммутатор будет работать с профилями с номерами 20, 40, 50 | + | коммутатор будет работать с профилями с номерами 20, 40, 50:<br /> |
- | при открытии шлюза добавляются правила 20, 40 и удаляется правило 50 | + | при открытии шлюза добавляются правила 20, 40 и удаляется правило 50<br /> |
- | при закрытии шлюза добавляются правила 20, 50 и удаляется правило 40 | + | при закрытии шлюза добавляются правила 20, 50 и удаляется правило 40<br /> |
при удалении шлюза удаляются правила 20, 40, 50 | при удалении шлюза удаляются правила 20, 40, 50 | ||
== Текст скрипта == | == Текст скрипта == | ||
+ | <source lang="bash"> | ||
+ | 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.bean.ManadUtils; | ||
+ | import bitel.billing.server.ipn.bean.VlanManager; | ||
+ | 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; | ||
+ | |||
+ | /* | ||
+ | protected void doSync(){ | ||
+ | log.info( "script started" ); | ||
+ | }; | ||
+ | */ | ||
+ | |||
+ | protected void doSync(){ | ||
+ | log.info( "script started" ); | ||
+ | try | ||
+ | { | ||
+ | log.info( "script started 1" ); | ||
+ | host = gate.getHost(); | ||
+ | port = gate.getPort(); | ||
+ | |||
+ | |||
+ | DefaultServerSetup gateSetup = new DefaultServerSetup( gate.getConfig(), "\r\n" ); | ||
+ | |||
+ | |||
+ | pswd = gate.getKeyword(); | ||
+ | login = gateSetup.getStringValue( "login"); | ||
+ | |||
+ | |||
+ | |||
+ | result = new StringBuffer(); | ||
+ | |||
+ | |||
+ | if( log.isDebugEnabled() ) | ||
+ | { | ||
+ | log.info( gate.getId() + " gate: " + host + ":" + port + " login: " + login + " pswd: " + pswd ); | ||
+ | } | ||
+ | |||
+ | |||
+ | TelnetSession session = new TelnetSession( host, port); | ||
+ | session.setLoginPromptSequence( ":" ); | ||
+ | |||
+ | log.info( "before connect" ); | ||
+ | session.connect(); | ||
+ | log.info( "after connect" ); | ||
+ | |||
+ | result.append( session.doCommand( login ) ); | ||
+ | log.info( "after command" ); | ||
+ | |||
+ | |||
+ | session.setLoginPromptSequence( "#" ); | ||
+ | result.append( session.doCommand( pswd ) ); | ||
+ | log.info( "before pswd" ); | ||
+ | |||
+ | |||
+ | log.info( "execute commands" ); | ||
+ | doCommands( session, result, gateSetup); | ||
+ | |||
+ | |||
+ | |||
+ | //TODO commands here | ||
+ | |||
+ | session.setLoginPromptSequence( "****" ); | ||
+ | result.append( session.doCommand( "logout" ) ); | ||
+ | |||
+ | |||
+ | log.info( result.toString() ); | ||
+ | |||
+ | |||
+ | |||
+ | log.info( "ok" ); | ||
+ | } catch (Exception e) | ||
+ | { | ||
+ | |||
+ | throw new RuntimeException ( e ); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | private void doCommands( TelnetSession session, StringBuffer result, DefaultServerSetup gateSetup) | ||
+ | throws IOException, OperationTimedoutException | ||
+ | { | ||
+ | |||
+ | |||
+ | openAddress = gateSetup.getStringValue( "open.address", "255.255.255.255" ) ; | ||
+ | |||
+ | log.info( "openAddress = " + openAddress ); | ||
+ | |||
+ | |||
+ | uplinks = Utils.stringToIntegerList( gateSetup.getStringValue( "uplink" ) ); | ||
+ | |||
+ | |||
+ | ports = getUserList( statusList ); | ||
+ | |||
+ | |||
+ | //-----настройки, вообще надо перенести ихв конфиг------------------------------------------------------------------- | ||
+ | OpenRules = new String []{ "config access_profile profile_id 20 add access_id ${aid} packet_content_mask offset_0-15 0x0 0x0 0x0 0x0 offset_16-31 0x8060000 0x0 0x20000 0x0 offset_32-47 0x${ip_hex} 0x0 0x0 0x0 port ${port} permit", | ||
+ | |||
+ | //доступ к сети | ||
+ | "config access_profile profile_id 40 add access_id ${aid} ip source_ip ${ip} port ${port} permit", | ||
+ | |||
+ | //удаляем правило доступа только к биллингу | ||
+ | "config access_profile profile_id 50 delete access_id ${aid}" | ||
+ | }; | ||
+ | |||
+ | |||
+ | |||
+ | CloseRules = new String []{ | ||
+ | //arp reply | ||
+ | "config access_profile profile_id 20 add access_id ${aid} packet_content_mask offset_0-15 0x0 0x0 0x0 0x0 offset_16-31 0x8060000 0x0 0x20000 0x0 offset_32-47 0x${ip_hex} 0x0 0x0 0x0 port ${port} permit", | ||
+ | |||
+ | //доступ к биллингу | ||
+ | "config access_profile profile_id 50 add access_id ${aid} ip source_ip ${ip} destination_ip ${openAdress} port ${port} permit", | ||
+ | |||
+ | //удаляем правило доступа только к сети | ||
+ | "config access_profile profile_id 40 delete access_id ${aid}" | ||
+ | }; | ||
+ | |||
+ | |||
+ | RemoveRules = new String []{ | ||
+ | //arp reply | ||
+ | "config access_profile profile_id 20 delete access_id ${aid}", | ||
+ | |||
+ | //удаляем правило доступа биллингу | ||
+ | "config access_profile profile_id 50 delete access_id ${aid}", | ||
+ | |||
+ | //удаляем правило доступа только к сети | ||
+ | "config access_profile profile_id 40 delete access_id ${aid}" | ||
+ | }; | ||
+ | |||
+ | //--------------------------------------------------------------------------------------------------------------------- | ||
+ | int j=1; | ||
+ | for( UserPortStatus port : ports ) | ||
+ | { | ||
+ | log.info("port.ipAddr=" + port.ipAddr); | ||
+ | |||
+ | switch (port.status.status) { | ||
+ | case IPNContractStatus.STATUS_OPEN: ApplyRules = OpenRules; log.info("open_user"); break; | ||
+ | case IPNContractStatus.STATUS_REMOVED: ApplyRules = RemoveRules; log.info("remove_user"); break; | ||
+ | default: ApplyRules = CloseRules; log.info("close_user"); break; | ||
+ | }; | ||
+ | |||
+ | for (i = 0; i < ApplyRules.length; i++){ | ||
+ | // for (String proto_rule : ApplyRules){ | ||
+ | ip_hex=Convert2hex(port.ipAddr); | ||
+ | rule=setValues(ApplyRules[i], port.port, port.ipAddr, openAddress, ip_hex , j); | ||
+ | |||
+ | log.info("rule=" + rule); | ||
+ | result.append( session.doCommand( rule ) ); | ||
+ | |||
+ | } | ||
+ | j=j+1; | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | |||
+ | |||
+ | private String setValues( String rule, int port, String ip, String openAddress, String ip_hex , int mod) | ||
+ | { | ||
+ | aid=26*mod+port; | ||
+ | rule = rule.replaceAll( "\\$\\{port\\}", String.valueOf( port ) ); | ||
+ | rule = rule.replaceAll( "\\$\\{ip\\}" , ip ); | ||
+ | rule = rule.replaceAll( "\\$\\{openAdress\\}", openAddress ); | ||
+ | rule = rule.replaceAll( "\\$\\{ip_hex\\}", ip_hex ); | ||
+ | rule = rule.replaceAll( "\\$\\{aid\\}", String.valueOf(aid) ); | ||
+ | return rule; | ||
+ | } | ||
+ | |||
+ | |||
+ | private String Convert2hex( String ip ){ | ||
+ | addr=InetAddress.getByName(ip); | ||
+ | bytes=addr.getAddress(); | ||
+ | str=""; | ||
+ | for(b : bytes){ | ||
+ | str=str+b2h(b & 0xff); | ||
+ | } | ||
+ | return str; | ||
+ | } | ||
+ | |||
+ | private String b2h( b ){ | ||
+ | hexChars = new String []{ "0", "1", "2", "3", "4", "5", "6", "7", "8","9", "A", "B", "C", "D", "E", "F" }; | ||
+ | return (hexChars[b/16]+hexChars[b%16]); | ||
+ | } | ||
+ | |||
+ | |||
+ | protected void doParentSync() | ||
+ | { | ||
+ | } | ||
+ | |||
+ | public List getUserList( List statusList ) | ||
+ | { | ||
+ | List userList = new ArrayList(); | ||
+ | for( UserStatus status : statusList ) | ||
+ | { | ||
+ | String rule = status.rule.getRuleText(); | ||
+ | StringTokenizer st = new StringTokenizer( rule, ";" ); | ||
+ | |||
+ | while( st.hasMoreTokens() ) | ||
+ | { | ||
+ | String token = st.nextToken().trim(); | ||
+ | data = token.split( ":" ); | ||
+ | if( data.length == 2 ) | ||
+ | { | ||
+ | UserPortStatus portStatus = new UserPortStatus(); | ||
+ | portStatus.port = Utils.parseIntString( data[0] ); | ||
+ | portStatus.ipAddr = data[1]; | ||
+ | portStatus.status = status; | ||
+ | userList.add( portStatus ); | ||
+ | } | ||
+ | else if ( data.length == 3 ) | ||
+ | { | ||
+ | UserPortStatus portStatus = new UserPortStatus(); | ||
+ | portStatus.port = Utils.parseIntString( data[0] ); | ||
+ | portStatus.macAddr = data[1].toUpperCase().replaceAll( "\\-", " " ); | ||
+ | portStatus.ipAddr = data[2]; | ||
+ | portStatus.status = status; | ||
+ | userList.add( portStatus ); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | return userList; | ||
+ | } | ||
+ | </source> |
Текущая версия на 17:54, 1 января 2009
Данный скрипт написан на основе скрипта Реалиазация_скриптовго_шлюза_для_коммутаторов_DES-3526,_DES-3550,_DES-3828,_DES-3852,_DGS-3200-10_и_им_подобных.
Содержание |
Задача
При разработке данного скрита решались следующие задачи:
- уменьшение объема скрипта за счет унификации кода, выполняемого при разных командах (открытие, закрытие, удаление);
- разделение кода скрипта и правил для коммутатора;
- возможность добавления нескольких IP-адресов на один порт.
Недостатки и недоделки
- правила для коммутатора вводятся все-таки в текст скрипта, а не в конфигурацию шлюза
- нельзя прописать один порт для разных договоров
- все манипуляции с IP-адресами договора надо проводить при состоянии его шлюза в положении удален (иначе некоторые записи в коммутаторе останутся до его перезагрузки)
- подключение к свитчу занимает 5 секунд (наверное это уже проблема в в биллинге - возможно он лезет к DNS)
- скрипт не проверяет текущее состояние коммутатора, а каждый раз загружает в него нужные команды
- в боевом режиме оно еще не проверялось
- не проверялось работа с ipn_dhcp (option82) - предполагается что при одном адресе на порт клиент будет автоматически получать IP, а при нескольких адресах (а это не является массовой услугой) прописывать адреса вручную
Предварительная настройка коммутатора
# этим правилом мы будем разрешать arp_reply c адресом абонента # это правила нужно тк абоненты (или вирусы на их компах) частенько присваивают себе адрес шлюза create access_profile packet_content_mask offset_0-15 0x0 0x0 0x0 0x0 offset_16-31 0xFFFF0000 0x0 0xFFFF0000 0x0 offset_32-47 0xFFFFFFFF 0x0 0x0 0x0 profile_id 20 #блокировка dhcp ответов и разрешение dhcp запросов (они могут отправляться не с IP-адреса пользователя) create access_profile ip udp dst_port_mask 0xFFFF profile_id 30 config access_profile profile_id 30 add access_id 1 ip udp dst_port 68 port 1 deny ... config access_profile profile_id 30 add access_id 24 ip udp dst_port 68 port 24 deny config access_profile profile_id 30 add access_id 101 ip udp dst_port 67 port 1 permit ... config access_profile profile_id 30 add access_id 124 ip udp dst_port 67 port 24 permit #правило для разрешения доступа пользователя к сети create access_profile ip source_ip_mask 255.255.255.255 profile_id 40 #правило для разрешения доступа пользователя к статистике create access_profile ip source_ip_mask 255.255.255.255 destination_ip_mask 255.255.255.0 profile_id 50 #разрешение arp-запросов create access_profile packet_content_mask offset_0-15 0x0 0x0 0x0 0x0 offset_16-31 0xFFFF0000 0x0 0xFFFF0000 0x0 profile_id 60 config access_profile profile_id 60 add access_id 1 packet_content_mask offset_0-15 0x0 0x0 0x0 0x0 offset_16-31 0x8060000 0x0 0x10000 0x0 port 1 permit .... config access_profile profile_id 60 add access_id 24 packet_content_mask offset_0-15 0x0 0x0 0x0 0x0 offset_16-31 0x8060000 0x0 0x10000 0x0 port 24 permit #блокируем всю остальную активность пользователя create access_profile ethernet source_mac 00-00-00-00-00-00 profile_id 200 config access_profile profile_id 200 add access_id 1 ethernet source_mac 00-00-00-00-00-00 port 1 deny config access_profile profile_id 200 add access_id 24 ethernet source_mac 00-00-00-00-00-00 port 24 deny
коммутатор будет работать с профилями с номерами 20, 40, 50:
при открытии шлюза добавляются правила 20, 40 и удаляется правило 50
при закрытии шлюза добавляются правила 20, 50 и удаляется правило 40
при удалении шлюза удаляются правила 20, 40, 50
Текст скрипта
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.bean.ManadUtils; import bitel.billing.server.ipn.bean.VlanManager; 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; /* protected void doSync(){ log.info( "script started" ); }; */ protected void doSync(){ log.info( "script started" ); try { log.info( "script started 1" ); host = gate.getHost(); port = gate.getPort(); DefaultServerSetup gateSetup = new DefaultServerSetup( gate.getConfig(), "\r\n" ); pswd = gate.getKeyword(); login = gateSetup.getStringValue( "login"); result = new StringBuffer(); if( log.isDebugEnabled() ) { log.info( gate.getId() + " gate: " + host + ":" + port + " login: " + login + " pswd: " + pswd ); } TelnetSession session = new TelnetSession( host, port); session.setLoginPromptSequence( ":" ); log.info( "before connect" ); session.connect(); log.info( "after connect" ); result.append( session.doCommand( login ) ); log.info( "after command" ); session.setLoginPromptSequence( "#" ); result.append( session.doCommand( pswd ) ); log.info( "before pswd" ); log.info( "execute commands" ); doCommands( session, result, gateSetup); //TODO commands here session.setLoginPromptSequence( "****" ); result.append( session.doCommand( "logout" ) ); log.info( result.toString() ); log.info( "ok" ); } catch (Exception e) { throw new RuntimeException ( e ); } }; private void doCommands( TelnetSession session, StringBuffer result, DefaultServerSetup gateSetup) throws IOException, OperationTimedoutException { openAddress = gateSetup.getStringValue( "open.address", "255.255.255.255" ) ; log.info( "openAddress = " + openAddress ); uplinks = Utils.stringToIntegerList( gateSetup.getStringValue( "uplink" ) ); ports = getUserList( statusList ); //-----настройки, вообще надо перенести ихв конфиг------------------------------------------------------------------- OpenRules = new String []{ "config access_profile profile_id 20 add access_id ${aid} packet_content_mask offset_0-15 0x0 0x0 0x0 0x0 offset_16-31 0x8060000 0x0 0x20000 0x0 offset_32-47 0x${ip_hex} 0x0 0x0 0x0 port ${port} permit", //доступ к сети "config access_profile profile_id 40 add access_id ${aid} ip source_ip ${ip} port ${port} permit", //удаляем правило доступа только к биллингу "config access_profile profile_id 50 delete access_id ${aid}" }; CloseRules = new String []{ //arp reply "config access_profile profile_id 20 add access_id ${aid} packet_content_mask offset_0-15 0x0 0x0 0x0 0x0 offset_16-31 0x8060000 0x0 0x20000 0x0 offset_32-47 0x${ip_hex} 0x0 0x0 0x0 port ${port} permit", //доступ к биллингу "config access_profile profile_id 50 add access_id ${aid} ip source_ip ${ip} destination_ip ${openAdress} port ${port} permit", //удаляем правило доступа только к сети "config access_profile profile_id 40 delete access_id ${aid}" }; RemoveRules = new String []{ //arp reply "config access_profile profile_id 20 delete access_id ${aid}", //удаляем правило доступа биллингу "config access_profile profile_id 50 delete access_id ${aid}", //удаляем правило доступа только к сети "config access_profile profile_id 40 delete access_id ${aid}" }; //--------------------------------------------------------------------------------------------------------------------- int j=1; for( UserPortStatus port : ports ) { log.info("port.ipAddr=" + port.ipAddr); switch (port.status.status) { case IPNContractStatus.STATUS_OPEN: ApplyRules = OpenRules; log.info("open_user"); break; case IPNContractStatus.STATUS_REMOVED: ApplyRules = RemoveRules; log.info("remove_user"); break; default: ApplyRules = CloseRules; log.info("close_user"); break; }; for (i = 0; i < ApplyRules.length; i++){ // for (String proto_rule : ApplyRules){ ip_hex=Convert2hex(port.ipAddr); rule=setValues(ApplyRules[i], port.port, port.ipAddr, openAddress, ip_hex , j); log.info("rule=" + rule); result.append( session.doCommand( rule ) ); } j=j+1; } }; private String setValues( String rule, int port, String ip, String openAddress, String ip_hex , int mod) { aid=26*mod+port; rule = rule.replaceAll( "\\$\\{port\\}", String.valueOf( port ) ); rule = rule.replaceAll( "\\$\\{ip\\}" , ip ); rule = rule.replaceAll( "\\$\\{openAdress\\}", openAddress ); rule = rule.replaceAll( "\\$\\{ip_hex\\}", ip_hex ); rule = rule.replaceAll( "\\$\\{aid\\}", String.valueOf(aid) ); return rule; } private String Convert2hex( String ip ){ addr=InetAddress.getByName(ip); bytes=addr.getAddress(); str=""; for(b : bytes){ str=str+b2h(b & 0xff); } return str; } private String b2h( b ){ hexChars = new String []{ "0", "1", "2", "3", "4", "5", "6", "7", "8","9", "A", "B", "C", "D", "E", "F" }; return (hexChars[b/16]+hexChars[b%16]); } protected void doParentSync() { } public List getUserList( List statusList ) { List userList = new ArrayList(); for( UserStatus status : statusList ) { String rule = status.rule.getRuleText(); StringTokenizer st = new StringTokenizer( rule, ";" ); while( st.hasMoreTokens() ) { String token = st.nextToken().trim(); data = token.split( ":" ); if( data.length == 2 ) { UserPortStatus portStatus = new UserPortStatus(); portStatus.port = Utils.parseIntString( data[0] ); portStatus.ipAddr = data[1]; portStatus.status = status; userList.add( portStatus ); } else if ( data.length == 3 ) { UserPortStatus portStatus = new UserPortStatus(); portStatus.port = Utils.parseIntString( data[0] ); portStatus.macAddr = data[1].toUpperCase().replaceAll( "\\-", " " ); portStatus.ipAddr = data[2]; portStatus.status = status; userList.add( portStatus ); } } } return userList; }