Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 47 additions & 4 deletions docs/IPАдрес.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,33 +430,76 @@ IPv4 и обычного одноадресного IPv6 возвращает `
Возвращает представление адреса в семействе IPv6.

```bsl
.IPv6()
.IPv6(Префикс = Неопределено)
```

#### Параметры

- `Префикс` - необязательный IPv6-префикс преобразования по
[RFC 6052](https://www.rfc-editor.org/rfc/rfc6052.html). Допустимые длины:
`/32`, `/40`, `/48`, `/56`, `/64` и `/96`.

#### Возвращаемое значение

Новый [`IPАдрес`](IPАдрес.md). IPv4-адрес преобразуется в IPv6-адрес с отображённым
IPv4 без зоны; IPv6-адрес копируется с зоной.
IPv4 без зоны, если префикс не задан. С префиксом IPv4 размещается в IPv6 по RFC 6052,
октет `u` и суффикс заполняются нулями. IPv6-адрес копируется с зоной.

#### Исключения

- `argument.invalid_type`, если `Префикс` не является `IPПрефикс`;
- `argument.invalid_value`, если префикс относится к IPv4, имеет недопустимую длину
или для `/96` содержит ненулевые биты с 64 по 71.

#### Пример

```bsl
Новый IPАдрес("192.0.2.1").IPv6().ВСтроку(); // "::ffff:192.0.2.1"

Префикс = Новый IPПрефикс("64:ff9b::/96");
Новый IPАдрес("192.0.2.1").IPv6(Префикс).ВСтроку(); // "64:ff9b::c000:201"
```

### IPv4

Возвращает представление адреса в семействе IPv4.

```bsl
.IPv4()
.IPv4(Префикс = Неопределено)
```

#### Параметры

- `Префикс` - необязательный IPv6-префикс преобразования по
[RFC 6052](https://www.rfc-editor.org/rfc/rfc6052.html). Допустимые длины:
`/32`, `/40`, `/48`, `/56`, `/64` и `/96`.

#### Возвращаемое значение

Новый [`IPАдрес`](IPАдрес.md) либо `Неопределено`. IPv4-адрес копируется, из IPv6-адреса с отображённым
IPv4 извлекается IPv4-адрес без зоны, а для остальных IPv6-адресов возвращается
`Неопределено`.
`Неопределено`. Если префикс задан, IPv4 извлекается из IPv6 по RFC 6052.
Октет `u` и суффикс при извлечении не проверяются. Для адреса вне префикса
возвращается `Неопределено`.

Метод выполняет только битовое преобразование. Ограничения на применение общеизвестного
префикса из RFC 6052 §3 и политика безопасности остаются вызывающему коду.

#### Исключения

- `argument.invalid_type`, если `Префикс` не является `IPПрефикс`;
- `argument.invalid_value`, если префикс относится к IPv4, имеет недопустимую длину
или для `/96` содержит ненулевые биты с 64 по 71.

#### Пример

```bsl
Префикс = Новый IPПрефикс("64:ff9b::/96");
Новый IPАдрес("64:ff9b::a9fe:a9fe").IPv4(Префикс).ВСтроку(); // "169.254.169.254"

СовместимыйПрефикс = Новый IPПрефикс("::/96");
Новый IPАдрес("::7f00:1").IPv4(СовместимыйПрефикс).ВСтроку(); // "127.0.0.1"
```

### СоздатьПрефикс

Expand Down
133 changes: 129 additions & 4 deletions src/Классы/IPАдрес.os
Original file line number Diff line number Diff line change
Expand Up @@ -405,9 +405,26 @@

// Возвращает IPv6-представление IP-адреса.
//
// Параметры:
// Префикс - IPПрефикс, Неопределено - IPv6-префикс преобразования по RFC 6052.
//
// Возвращаемое значение:
// IPАдрес - IPv6-адрес; IPv4 преобразуется в IPv6 с отображённым IPv4 без зоны.
Функция IPv6() Экспорт
// IPАдрес - IPv6-адрес; без префикса IPv4 преобразуется в IPv6 с отображённым IPv4 без зоны.
//
// Исключения:
// argument.invalid_type - Префикс не является IPПрефикс.
// argument.invalid_value - Префикс не подходит для преобразования по RFC 6052.
Функция IPv6(Префикс = Неопределено) Экспорт

Если Префикс <> Неопределено Тогда
ПроверитьПрефиксПреобразования(Префикс);

Если ЭтоIPv6() Тогда
Возврат СоздатьАдресСЗоной(Зона());
КонецЕсли;

Возврат СоздатьIPv6ПоПрефиксу(Префикс);
КонецЕсли;

Если ЭтоIPv6() Тогда
Возврат СоздатьАдресСЗоной(Зона());
Expand All @@ -430,9 +447,27 @@

// Возвращает IPv4-представление IP-адреса, если оно существует.
//
// Параметры:
// Префикс - IPПрефикс, Неопределено - IPv6-префикс преобразования по RFC 6052.
//
// Возвращаемое значение:
// IPАдрес, Неопределено - IPv4-адрес или IPv4-адрес, отображённый в IPv6; иначе Неопределено.
Функция IPv4() Экспорт
// IPАдрес, Неопределено - IPv4-адрес; без префикса поддерживается отображение IPv4 в IPv6,
// с префиксом возвращается вложенный IPv4 или Неопределено, если IPv6-адрес вне префикса.
//
// Исключения:
// argument.invalid_type - Префикс не является IPПрефикс.
// argument.invalid_value - Префикс не подходит для преобразования по RFC 6052.
Функция IPv4(Префикс = Неопределено) Экспорт

Если Префикс <> Неопределено Тогда
ПроверитьПрефиксПреобразования(Префикс);

Если ЭтоIPv4() Тогда
Возврат Новый IPАдрес(_Октеты);
КонецЕсли;

Возврат ИзвлечьIPv4ПоПрефиксу(Префикс);
КонецЕсли;

Если ЭтоIPv4() Тогда
Возврат Новый IPАдрес(_Октеты);
Expand Down Expand Up @@ -555,6 +590,96 @@

#Область СлужебныеПроцедурыИФункции

Процедура ПроверитьПрефиксПреобразования(Префикс)

ПроверкаАргументов.ПроверитьТип("Префикс", Префикс, Тип("IPПрефикс"));

Если Не Префикс.БазовыйАдрес().ЭтоIPv6() Тогда
ВызватьИсключение СтандартныеОшибки.НедопустимоеЗначениеАргумента(
"Префикс",
"IPv6-префикс преобразования"
);
КонецЕсли;

ДлинаПрефикса = Префикс.ДлинаПрефикса();
Если Не ЭтоДопустимаяДлинаПрефиксаПреобразования(ДлинаПрефикса) Тогда
ВызватьИсключение СтандартныеОшибки.НедопустимоеЗначениеАргумента(
"Префикс",
"IPv6-префикс длиной 32, 40, 48, 56, 64 или 96 бит"
);
КонецЕсли;

Если ДлинаПрефикса = 96 Тогда
ОктетыПрефикса = Префикс.БазовыйАдрес().Октеты();
Если ОктетыПрефикса[8] <> 0 Тогда
ВызватьИсключение СтандартныеОшибки.НедопустимоеЗначениеАргумента(
"Префикс",
"IPv6-префикс с нулевым октетом u"
);
КонецЕсли;
КонецЕсли;

КонецПроцедуры

Функция ЭтоДопустимаяДлинаПрефиксаПреобразования(ДлинаПрефикса)

Возврат ДлинаПрефикса = 32
Или ДлинаПрефикса = 40
Или ДлинаПрефикса = 48
Или ДлинаПрефикса = 56
Или ДлинаПрефикса = 64
Или ДлинаПрефикса = 96;

КонецФункции

Функция СоздатьIPv6ПоПрефиксу(Префикс)

ОктетыПрефикса = Префикс.БазовыйАдрес().Октеты();
ОктетыIPv6 = Новый Массив(16);
Для Индекс = 0 По 15 Цикл
ОктетыIPv6[Индекс] = ОктетыПрефикса[Индекс];
КонецЦикла;

ИндексIPv6 = Префикс.ДлинаПрефикса() / 8;
Для ИндексIPv4 = 0 По 3 Цикл
Если ИндексIPv6 = 8 Тогда
ИндексIPv6 = ИндексIPv6 + 1;
КонецЕсли;

ОктетыIPv6[ИндексIPv6] = _Октеты[ИндексIPv4];
ИндексIPv6 = ИндексIPv6 + 1;
КонецЦикла;

Возврат Новый IPАдрес(ОктетыIPv6);

КонецФункции

Функция ИзвлечьIPv4ПоПрефиксу(Префикс)

ОктетыПрефикса = Префикс.БазовыйАдрес().Октеты();
Если Не ОперацииСОктетамиIPАдресов.СовпадаютСтаршиеБиты(
_Октеты,
ОктетыПрефикса,
Префикс.ДлинаПрефикса()
) Тогда
Возврат Неопределено;
КонецЕсли;

ОктетыIPv4 = Новый Массив;
ИндексIPv6 = Префикс.ДлинаПрефикса() / 8;
Для ИндексIPv4 = 0 По 3 Цикл
Если ИндексIPv6 = 8 Тогда
ИндексIPv6 = ИндексIPv6 + 1;
КонецЕсли;

ОктетыIPv4.Добавить(_Октеты[ИндексIPv6]);
ИндексIPv6 = ИндексIPv6 + 1;
КонецЦикла;

Возврат Новый IPАдрес(ОктетыIPv4);

КонецФункции

Функция СоздатьДанныеАдреса(Октеты, Зона)

Возврат Новый Структура("Октеты,Зона", Октеты, Зона);
Expand Down
Loading
Loading