Этот материал создан коллективными усилиями преподавателя и студента. Первый и четвертый этапы были разработаны студентом, второй и третий — преподавателем, а пятый этап — результат совместной работы.

Этап первый – событие или инцидент

Попав на второй курс, я начал полноценное обучение по своей специальности техника связи. И одним из важнейших направлений была IP адресация. Но к моему огромному сожалению, 95% времени мы обучались работе с протоколом IPv4, создавая сети, разбивая их на подсети и изучая специфику этого протокола. Меня это беспокоило, ибо такой фокус на устаревающей технологии пагубно влияет на будущих специалистов.

На 3 курсе я ушёл заниматься кибербезопасностью в Skills Battles, где ещё больше узнал про IP адресацию и наконец то полноценно поработал с IPv6. После этого я загорелся идеей сделать что-то по протоколу IPv6, чтобы обычные обучающиеся узнавали про IPv6 и становились более подкованными в нём.

Этап второй - зачем это надо?

Я, как преподаватель дисциплины Компьютерные сети, понимала необходимость изучения протокола IPv6. Протокол IPv6 больше соответствует современным реалиям. Формат IPv6-адреса составляет 128 бит, которые представлены восемью шестнадцатибитными шестнадцатеричными блоками и разделены двоеточиями.

Если сравнивать с IPv4, то IPv6 имеет следующие достоинства:

  • маршрутизация становится более эффективной, поскольку пакеты передаются без необходимости фрагментации;

  • встроена технология QoS, для обеспечения эффективной передачи данных в условиях ограниченных возможностей сети;

  • устранён механизм преобразования сетевых адресов NAT;

  • упрощается администрирование сети благодаря автоконфигурации адресов;

  • уменьшаются затраты на обработку за счёт улучшенной структуры заголовков.

Всем понятно, что будущее за протоколом 6 версии. Но в учебных программах, большее количество часов отведено для изучения 4 версии.

Студентам скучно читать просто теоретический материал, да и скорость усвоения материала у всех разная. Поэтому было решено в рамках дипломного проектирования создать программу по изучению протокола IPv6.

Этап третий - постановка задачи

Мною, как руководителем дипломного проектирования, было разработано и выдано задание разработать приложение, в котором содержится лекционный материал, тесты и практические задания по теме «Протокол IPv6».

Приложение должно иметь функционал регистрации и авторизации пользователей, возможность сохранения результатов и прогресса учащихся, а также страницу для администратора. Администратор должен иметь возможность управлять учетными записями пользователей, просматривать их результаты и удалять пользователей при необходимости.

Этап четвертый - реализация

Так как я имел достаточно опыта в работе с фреймворком для разработки веб приложений – Django, я выбрал его для реализации своей задачи.

В качестве базы данных я выбрал PostgreSQL. Django позволяет легко и быстро создавать приложения и мне отдельно нравится в нём его система маршрутизации и реализация шаблона MVP (Model-View-Presenter). Изначально у меня не было предпочтений в выборе базы данных, но после изучения рынка я пришёл к PostgreSQL. Она была выбрана для получения опыта с релевантной на данный момент базой данных.

Итоговая база данных выглядит так

База данных
База данных

Было разработано 5 тем, каждая из которых затрагивает ключевые аспекты протокола IPv6.

Темы, затрагивающие протокол IPv6
Темы, затрагивающие протокол IPv6

Для усложнения жизни учащихся и повышения безопасности мной была создана защищённая маршрутизация. Доступ к лекциям, тестам и заданиям возможен только по POST запросам и система адресации Django и csrf токены позволяют так сделать.

Например система генерации и вывода заданий выглядит вот так.

def exercise(request):    
if request.POST.get('number') is None:       
return redirect('/')    
if request.session.get('auth') and request.method == 'POST':        
form = dict(request.POST)        
num = int(form.get('number')[0])       
if num == 3:           
addresses = RecordingAddresses.objects.order_by('?')[:12]     
id_addresses = []            
f_addresses = []            
a_addresses = []         
i = 0           
for address in addresses:              
id_addresses.append(address.id)         
if i < len(addresses) / 2:                
f_addresses.append(address.full_record)      
else:                 
a_addresses.append(address.abbreviation)           
i += 1         
request.session["id_addresses"] = id_addresses     
return render(request, 'tasks/task3.html',             
{'auth': request.session.get('auth'), "f_addresses": f_addresses, 
"a_addresses": a_addresses})     
if num == 4:          
task_4_data = []           
task_texts = []            
for i in range(3):               
type_task = random.choice([True, False])  # True - 4 бита False - 5 битов    
if type_task:              
type_task_text = "подсети "               
else:                    
type_task_text = "интерфейса "             
addresses_names = 
['a136', 'b062', '7f8c', '974c', 'ff0d', 'cb8b', '8e51', 'afbc',   
'11ae', '153f', 'a39f', 'fc97', '0445', '1d4c', '6209', 'ab7a',   
'5dc3', '9692', 'd4f1', 'af91', '3c97', '4a0f', '5b60', 'b72b',  
'ed0c', '149c', '15dc', '1e69', '687d', 'ba80', '99b9', 'cc8a',   
'6358', 'f32e', 'aa29', '4c49', 'b88d', '970e', '3a78', 'f88c',   
'b89c', 'da45', '73b6', '180a', '9df3', '85e6', '7f34', '1608',  
'd8dd', '719c', '5138', '3f2c', 'a6e8', '22a9', '4eed', '2993', 
'f3f8', '5710', '4acc', '2a75', '50a6', '7d28', '8a33', 'fe9a',  
'e424', '7d97', '252b', '89f7', '5bd6', '1e4a', '734d', '6bd3',   
'1870', 'a633', 'b6b4', '15bf', '7494', '0c7d', '8d98', '2def',   
'0ee5', '378b', '8f7d', '6835', 'b0c1', 'f451', 'cc42', '2f39',  
'8d51', 'b269', '9729', 'eedc', 'ee80', 'bc4b', 'ce67', 'af69',  
'0054', '2329', '7361', '4cbb', 'c368', '7f27', 'a042', 'c5d0',  
'3057', 'ee51', 'f62c', '6b13', '1fd0', 'ca8a', '1d23', '3e33',  
'1030', '7d04', '61de', '3ae1', '960b', '229f', 'caab', '0000',   
'ca32', 'f177', '09f1', '5242', '2883', 'ca35', '2df6', 'bd86']     
random.shuffle(addresses_names)             
address_name = addresses_names[0] + ':' + addresses_names[1] + ':' + addresses_names[1]                
number_of_subnets = random.randint(17, 4080)     
task_text = "Произведите разбиение сети " + address_name + ":: на подсети с использованием идентификатора " + type_task_text + "и укажите " + str(            
number_of_subnets) + " подсеть."         
task_texts.append(task_text)              
task_4_data.append([type_task, address_name, number_of_subnets]) 
request.session["task_4_data"] = task_4_data        
return render(request, 'tasks/task4.html',            
{'auth': request.session.get('auth'), "tasks": task_texts})  
return render(request, 'tasks/task' + str(num) + '.html', {'auth': request.session.get('auth')})    
else:        
return redirect('/login')

Теперь перейдём к заданиям. Они присутствуют только в 2, 3 и 4 темах.

В задании 2 темы нужно заполнить поля заголовка и указать размеры.

Вот так проходит обработка формы

task = Task.objects.filter(task_number=str(num)).first()    
answers = json.loads(task.task_answer)  
for i in range(8):       
if str(form.get('formChoice' + str(i + 1))[0]) == str(answers['naming'][i]):  
result_task += 1     
if str(form.get('size' + str(i + 1))[0]) == str(answers['len'][i]): 
result_task += 1    
grade = calculation_result(16, result_task)if num == 3:    for i in range(12): 
address = RecordingAddresses.objects.filter(id=request.session["id_addresses"][i]).first()   
if i < 6 and str.strip(form['address'][i].lower()) == str.strip(address.abbreviation):       
result_task += 1   
if i >= 6 and str.strip(form['address'][i].lower()) == str.strip(address.full_record):         
result_task += 1  
grade = calculation_result(12, result_task)
task_answer = TaskAnswer(task_result=grade, task_id_id=Task.objects.filter(task_number=num).first().id,     
user_id_id=request.session['id'])task_answer.save()if grade > "2":  
user = User.objects.get(id=request.session['id'])   
user.theme_status = user.theme_status[:num - 1] + '1' + user.theme_status[num:]   
user.save(update_fields=["theme_status"])return render(request, 'result_task_page.html',         
{'result': grade, 'number': num})

В задании 3 темы необходимо сократить и восстановить по 6 адресов.

Для генерации адресов используется вот этот код

addresses = RecordingAddresses.objects.order_by('?')[:12]
id_addresses = []
f_addresses = []
a_addresses = []
i = 0for address in addresses:   
id_addresses.append(address.id)    
if i < len(addresses) / 2:     
f_addresses.append(address.full_record) 
else:       
a_addresses.append(address.abbreviation)  
i += 1request.session["id_addresses"] = id_addressesreturn render(request, 'tasks/task3.html',     
{'auth': request.session.get('auth'), "f_addresses": f_addresses, "a_addresses": a_addresses})

А для проверки корректности используется этот код

for i in range(12):   
address = RecordingAddresses.objects.filter(id=request.session["id_addresses"][i]).first()   
if i < 6 and str.strip(form['address'][i].lower()) == str.strip(address.abbreviation):    
result_task += 1 
if i >= 6 and str.strip(form['address'][i].lower()) == str.strip(address.full_record):   
result_task += 1grade = calculation_result(12, result_task)

Задание 4 темы требует разбиение сети на подсети и указание последней

Данный код генерирует сети и необходимое количество подсетей

task_4_data = []task_texts = []for i in range(3):    
type_task = random.choice([True, False])  # True - 4 бита False - 5 битов 
if type_task:        
type_task_text = "подсети "  
else:     
type_task_text = "интерфейса "    
addresses_names = ['a136', 'b062'] # Их больше    
random.shuffle(addresses_names) 
address_name = addresses_names[0] + ':' + addresses_names[1] + ':' + addresses_names[1]  
number_of_subnets = random.randint(17, 4080)  
task_text = "Произведите разбиение сети " + address_name + ":: на подсети с использованием идентификатора " + type_task_text + "и укажите " + str(        number_of_subnets) + " подсеть."   
task_texts.append(task_text) 
task_4_data.append([type_task, address_name, number_of_subnets])request.session["task_4_data"] = task_4_datareturn render(request, 'tasks/task4.html',     
{'auth': request.session.get('auth'), "tasks": task_texts})

А данный код проверяет выполненную работу

i = 0for task_data in request.session["task_4_data"]:  
number_of_subnets_hex = hex(int(task_data[2]))[2:]  # True - 4 бита False - 5 битов
subnet = ":0000:0"   
len_num_sub = len(number_of_subnets_hex)   
if task_data[0]:      
subnet = subnet[:len(subnet) - len_num_sub - 2] + str(number_of_subnets_hex) + ":0"  
else:      
subnet = (subnet[:len(subnet) - len_num_sub - 1] +   
str(number_of_subnets_hex[:len_num_sub - 1]) +         
":" + number_of_subnets_hex[len_num_sub - 1:len_num_sub])   
ans_address = task_data[1] + subnet + "000:0000:0000:0000"    
try:        
if ipaddress.IPv6Address(ans_address) == ipaddress.IPv6Address(form.get('address')[i]):   
result_task += 1  
except:    
print("Nop") 
i += 1grade = 2 + result_task

Этап пятый - тестирование

Когда Веб приложение было готово, мы протестировали его с помощью студентов-добровольцев. Студенты критичных проблем не выявили. По их отзывам программа интересная, материал дан в доступной форме, а также есть возможность проверить свои знания и умения с помощью тестов и практических заданий.

Веб приложение доступно в открытом репозитории Github https://github.com/GoshArt/DiplomIPv6/

Комментарии (6)


  1. Vindicar
    08.05.2024 12:54
    +1

    Как преподаватель скажу: программка ничего так. Абсолютно стандартная база для тестов с парой типов вопросов. На курсовой сойдёт, но не более того. На диплом - даже четвёрка будет с большой натяжкой, разве что специальность студента не связана напрямую с разработкой ПО. Косвенно подтверждается тем, что на гитхабе коммиты идут с середины января по середину февраля. Ну не бывает так, чтобы серьёзный диплом написали так быстро. =)

    Во-первых, вся функциональность прекрасно реализуется тем же Moodle. В том числе генерация случайных заданий по формуле. Мудлом сейчас довольно активно пользуются для организации дистанционного обучения, так что вопрос про конкурентный анализ был бы задан одним из первых. А поскольку это опенсорсный движок, обычная отмазка про зависимость от сервис-провайдера не сработала бы.

    Во-вторых, хардкод. Его много. Код проверки заданий на подсети содержит захардкоженные строки. Т.е. число нулей в адресе всегда одинаково? Тогда несколько страдает вариативность задания. Захардкожено то, что число заданий по сокращению и развёртыванию IPv6 адресов всегда равное. Захардкожено преобразование процентов в шкалу оценок 2-3-4-5. Захардкожены части адреса для генерации. Хотя тут я вижу почему - это гарантирует, что не проявится ноль, где не нужно, и не изменит ответ.

    Ну и до кучи, очень небрежно оформлен пост, просто "на, отвали". Код нечитаем: команды в кучу по нескольку строк, отступы уехали, ссылка в конце кривая и ведёт не куда нужно. Да и на кой код в посте, если есть ссылка на гитхаб?

    В общем, удивлён, откуда +5 у поста.


    1. zvzd Автор
      08.05.2024 12:54

      Здравствуйте. Спасибо большое, за замечания.


  1. Mamonthful
    08.05.2024 12:54

    NAT имеет и другой функционал, помимо экономии адресов. Это важный элемент безопасности, скрывающий внутреннюю структуру сети. Так что он будет применяться и дальше


    1. omgiafs
      08.05.2024 12:54
      +2

      Тут сейчас правильные сетевики придут и объяснят, что NAT - это не про безопасность и что думать в таком ключе вредно. И что в IPv6 эта структура тоже вполне себе скрывается. И что у устройства есть локальный и глобальный IPv6 адреса и ещё много интересных штук.


  1. jackcrane
    08.05.2024 12:54

    1) сколько % заданий решается через ip калькулятор ?

    2) сколько % заданий решается через сниффер ?

    3) знают ли соавторы, как называется заучивание этого наизусть ?

    но вы продолжайте в том же направлении. и чтобы модель OSI от зубов отлетала.


  1. slonopotamus
    08.05.2024 12:54

    У вас отступы в листингах кода сломались. И подсветку синтаксиса неплохо бы включить.