Модифицированный скриптовый шлюз для DES-3526 и подобных

Материал из BiTel WiKi

(Различия между версиями)
Перейти к: навигация, поиск
(Предварительная настройка коммутатора)
(Недостатки и недоделки)
 
(8 промежуточных версий не показаны.)
Строка 4: Строка 4:
При разработке данного скрита решались следующие задачи: <br />
При разработке данного скрита решались следующие задачи: <br />
-
1)уменьшение объема скрипта за счет унификации кода, выполняемого при разных командах (открытие, закрытие, удаление);<br />
+
# уменьшение объема скрипта за счет унификации кода, выполняемого при разных командах (открытие, закрытие, удаление);<br />
-
2)разделение кода скрипта и правил для коммутатора;<br />
+
# разделение кода скрипта и правил для коммутатора;<br />
-
3)возможность  добавления нескольких ip-адресов на один порт.
+
# возможность  добавления нескольких IP-адресов на один порт.
== Недостатки и недоделки ==
== Недостатки и недоделки ==
-
1) правила для коммутатора вводятся все-таки в текст скрипта, а не в конфигурацию шлюза<br />
+
#правила для коммутатора вводятся все-таки в текст скрипта, а не в конфигурацию шлюза<br />
-
2) нельзя прописать один порт для разных договоров<br />
+
#нельзя прописать один порт для разных договоров<br />
-
3) все манипуляции с IP-адресами договора надо проводить при состоянии его шлюза в положении удален (иначе некоторые записи в коммутаторе останутся до его перезагрузки)<br />
+
#все манипуляции с IP-адресами договора надо проводить при состоянии его шлюза в положении удален (иначе некоторые записи в коммутаторе останутся до его перезагрузки)<br />
-
4) подключение к свитчу занимает 5 секунд (наверное это уже проблема в в биллинге - возможно он лезет к DNS)<br />
+
#подключение к свитчу занимает 5 секунд (наверное это уже проблема в в биллинге - возможно он лезет к DNS)<br />
-
5) скрипт не проверяет текущее состояние коммутатора, а каждый раз загружает в него нужные команды<br />
+
#скрипт не проверяет текущее состояние коммутатора, а каждый раз загружает в него нужные команды<br />
-
6) в боевом режиме оно еще не проверялось <br />
+
#в боевом режиме оно еще не проверялось <br />
-
7) не проверялось работа с ipn_dhcp (option82) - предполагается что при одном адресе на порт клиент будет автоматически получать IP, а при нескольких адресах (а это не является массовой услугой) прописывать адреса вручную<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
 +
Строка 46: Строка 51:
config access_profile profile_id 200 add access_id 24 ethernet source_mac 00-00-00-00-00-00 port 24 deny
config access_profile profile_id 200 add access_id 24 ethernet source_mac 00-00-00-00-00-00 port 24 deny
</source>
</source>
 +
 +
коммутатор будет работать с профилями с номерами 20, 40, 50:<br />
 +
при открытии шлюза добавляются правила 20, 40 и удаляется правило 50<br />
 +
при закрытии шлюза добавляются правила 20, 50 и удаляется правило 40<br />
 +
при удалении шлюза удаляются правила 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_и_им_подобных.

Содержание

Задача

При разработке данного скрита решались следующие задачи:

  1. уменьшение объема скрипта за счет унификации кода, выполняемого при разных командах (открытие, закрытие, удаление);
  2. разделение кода скрипта и правил для коммутатора;
  3. возможность добавления нескольких IP-адресов на один порт.

Недостатки и недоделки

  1. правила для коммутатора вводятся все-таки в текст скрипта, а не в конфигурацию шлюза
  2. нельзя прописать один порт для разных договоров
  3. все манипуляции с IP-адресами договора надо проводить при состоянии его шлюза в положении удален (иначе некоторые записи в коммутаторе останутся до его перезагрузки)
  4. подключение к свитчу занимает 5 секунд (наверное это уже проблема в в биллинге - возможно он лезет к DNS)
  5. скрипт не проверяет текущее состояние коммутатора, а каждый раз загружает в него нужные команды
  6. в боевом режиме оно еще не проверялось
  7. не проверялось работа с 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;
}
Личные инструменты