windows-nt/Source/XPSP1/NT/net/tcpip/samples/rtchange/rtchange.c

380 lines
11 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 2000, Microsoft Corporation
Module Name:
rtchange.c
Abstract:
This module contains a program demonstrating the use of the TCP/IP driver's
route-change notification facilities.
Author:
Abolade Gbadegesin (aboladeg) 15-April-2000
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <ntddip.h>
#include <ipinfo.h>
char*
ntoa(
ULONG IpAddress
)
{
return inet_ntoa(*(struct in_addr*)&IpAddress);
}
NTSTATUS
NotifyRouteChange(
HANDLE FileHandle,
ULONG IoControlCode,
ULONG NotifyIpAddress,
BOOLEAN OutputRequired
)
{
HANDLE EventHandle;
PVOID InputBuffer;
ULONG InputBufferLength;
IO_STATUS_BLOCK IoStatus;
IPNotifyData NotifyData = {0};
IPRouteNotifyOutput NotifyOutput = {0};
PVOID OutputBuffer;
ULONG OutputBufferLength;
NTSTATUS Status;
if (NotifyIpAddress == INADDR_NONE) {
InputBuffer = NULL;
InputBufferLength = 0;
} else if (NotifyIpAddress == INADDR_ANY) {
NotifyData.Add = 0;
InputBuffer = &NotifyData;
InputBufferLength = sizeof(NotifyData);
} else {
NotifyData.Add = NotifyIpAddress;
InputBuffer = &NotifyData;
InputBufferLength = sizeof(NotifyData);
}
if (OutputRequired) {
OutputBuffer = &NotifyOutput;
OutputBufferLength = sizeof(NotifyOutput);
} else {
OutputBuffer = NULL;
OutputBufferLength = 0;
}
Status =
NtCreateEvent(
&EventHandle, EVENT_ALL_ACCESS, NULL,
SynchronizationEvent, FALSE
);
if (!NT_SUCCESS(Status)) {
printf("NtCreateEvent=%x\n", Status);
} else {
Status =
NtDeviceIoControlFile(
FileHandle,
EventHandle,
NULL,
NULL,
&IoStatus,
IOCTL_IP_RTCHANGE_NOTIFY_REQUEST,
InputBuffer,
InputBufferLength,
OutputBuffer,
OutputBufferLength
);
if (Status == STATUS_PENDING) {
printf("NtDeviceIoControlFile=%x, waiting\n", Status);
NtWaitForSingleObject(EventHandle, FALSE, NULL);
Status = IoStatus.Status;
}
printf("NtDeviceIoControlFile=%x\n", Status);
NtClose(EventHandle);
if (NT_SUCCESS(Status) && OutputRequired) {
printf("\tDestination: %s\n", ntoa(NotifyOutput.irno_dest));
printf("\tMask: %s\n", ntoa(NotifyOutput.irno_mask));
printf("\tNext-hop: %s\n", ntoa(NotifyOutput.irno_nexthop));
printf("\tProtocol: %d\n", NotifyOutput.irno_proto);
printf("\tIndex: %d\n", NotifyOutput.irno_ifindex);
}
}
return Status;
}
typedef struct {
IO_STATUS_BLOCK IoStatus;
IPRouteNotifyOutput NotifyOutput;
} ROUTE_NOTIFY_CONTEXT, *PROUTE_NOTIFY_CONTEXT;
VOID NTAPI
NotifyRouteCompletionRoutine(
PVOID Context,
PIO_STATUS_BLOCK IoStatus,
ULONG Reserved
)
{
PROUTE_NOTIFY_CONTEXT NotifyContext = (PROUTE_NOTIFY_CONTEXT)Context;
printf("NotifyRouteCompletionRoutine(%p, %x)\n", Context, IoStatus->Status);
if (NT_SUCCESS(IoStatus->Status)) {
PIPRouteNotifyOutput NotifyOutput = &NotifyContext->NotifyOutput;
printf("\tDestination: %s\n", ntoa(NotifyOutput->irno_dest));
printf("\tMask: %s\n", ntoa(NotifyOutput->irno_mask));
printf("\tNext-hop: %s\n", ntoa(NotifyOutput->irno_nexthop));
printf("\tProtocol: %d\n", NotifyOutput->irno_proto);
printf("\tIndex: %d\n", NotifyOutput->irno_ifindex);
}
}
ULONG
QueueNotifyRouteChange(
HANDLE FileHandle,
IPNotifyVersion Version,
ULONG NotificationCount
)
{
ULONG i;
PVOID InputBuffer;
ULONG InputBufferLength;
PROUTE_NOTIFY_CONTEXT NotifyContext;
IPNotifyData NotifyData = {0};
PVOID OutputBuffer;
ULONG OutputBufferLength;
NTSTATUS Status;
NotifyData.Version = Version;
NotifyData.Add = 0;
InputBuffer = &NotifyData;
InputBufferLength = sizeof(NotifyData);
for (i = 0; i < NotificationCount; i++) {
NotifyContext = (PROUTE_NOTIFY_CONTEXT)malloc(sizeof(*NotifyContext));
if (!NotifyContext) {
printf("QueueNotifyRouteChange: malloc=<null>\n");
break;
} else {
printf("QueueNotifyRouteChange: queuing %p\n", NotifyContext);
ZeroMemory(NotifyContext, sizeof(*NotifyContext));
Status =
NtDeviceIoControlFile(
FileHandle,
NULL,
NotifyRouteCompletionRoutine,
NotifyContext,
&NotifyContext->IoStatus,
IOCTL_IP_RTCHANGE_NOTIFY_REQUEST,
InputBuffer,
InputBufferLength,
&NotifyContext->NotifyOutput,
sizeof(NotifyContext->NotifyOutput)
);
printf("NtDeviceIoControlFile=%x\n", Status);
}
}
return i;
}
int __cdecl
main(
int argc,
char* argv[]
)
{
HANDLE FileHandle;
IO_STATUS_BLOCK IoStatus;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
UNICODE_STRING UnicodeString;
//
// Open a handle to the IP device-object.
//
RtlInitUnicodeString(&UnicodeString, DD_IP_DEVICE_NAME);
InitializeObjectAttributes(
&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status =
NtCreateFile(
&FileHandle,
GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE,
&ObjectAttributes,
&IoStatus,
NULL,
0,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN_IF,
0,
NULL,
0
);
if (!NT_SUCCESS(Status)) {
printf("NtCreateFile=%x\n", Status);
return 0;
}
//
// Continually prompt for instructions until interrupted.
//
for (;;) {
ULONG Selection;
BOOLEAN OutputRequired = TRUE;
IPNotifyVersion Version = IPNotifySynchronization;
printf("Simple route-change notification:\n");
printf("\t1. Submit NULL route-change request [no output]\n");
printf("\t2. Submit NULL route-change request\n");
printf("\t3. Submit general route-change request [no output]\n");
printf("\t4. Submit general route-change request\n");
printf("\t5. Submit specific route-change request [no output]\n");
printf("\t6. Submit specific route-change request\n");
printf("Extended route-change notification:\n");
printf("\t7. Submit NULL route-change request [no output]\n");
printf("\t8. Submit NULL route-change request\n");
printf("\t9. Submit general route-change request [no output]\n");
printf("\t10. Submit general route-change request\n");
printf("\t11. Submit specific route-change request [no output]\n");
printf("\t12. Submit specific route-change request\n");
printf("\t13. Submit multiple general route-change requests\n");
printf("\t using 'notification' semantics.\n");
printf("\t14. Submit multiple general route-change requests\n");
printf("\t using 'synchronization' semantics.\n");
printf("\nEnter selection: ");
if (!scanf("%d", &Selection)) {
break;
}
switch(Selection) {
case 1:
OutputRequired = FALSE;
case 2: {
Status =
NotifyRouteChange(
FileHandle, IOCTL_IP_RTCHANGE_NOTIFY_REQUEST,
INADDR_NONE, OutputRequired
);
printf("NotifyRouteChange=%x\n", Status);
break;
}
case 3:
OutputRequired = FALSE;
case 4: {
Status =
NotifyRouteChange(
FileHandle, IOCTL_IP_RTCHANGE_NOTIFY_REQUEST,
INADDR_ANY, OutputRequired
);
printf("NotifyRouteChange=%x\n", Status);
break;
}
case 5:
OutputRequired = FALSE;
case 6: {
UCHAR Destination[16];
printf("Enter destination: ");
if (!scanf("%s", Destination)) {
break;
}
Status =
NotifyRouteChange(
FileHandle, IOCTL_IP_RTCHANGE_NOTIFY_REQUEST,
inet_addr(Destination), OutputRequired
);
printf("NotifyRouteChange=%x\n", Status);
break;
}
case 7:
OutputRequired = FALSE;
case 8: {
Status =
NotifyRouteChange(
FileHandle, IOCTL_IP_RTCHANGE_NOTIFY_REQUEST_EX,
INADDR_NONE, OutputRequired
);
printf("NotifyRouteChange=%x\n", Status);
break;
}
case 9:
OutputRequired = FALSE;
case 10: {
Status =
NotifyRouteChange(
FileHandle, IOCTL_IP_RTCHANGE_NOTIFY_REQUEST_EX,
INADDR_ANY, OutputRequired
);
printf("NotifyRouteChange=%x\n", Status);
break;
}
case 11:
OutputRequired = FALSE;
case 12: {
UCHAR Destination[16];
printf("Enter destination: ");
if (!scanf("%s", Destination)) {
break;
}
Status =
NotifyRouteChange(
FileHandle, IOCTL_IP_RTCHANGE_NOTIFY_REQUEST_EX,
inet_addr(Destination), OutputRequired
);
printf("NotifyRouteChange=%x\n", Status);
break;
}
case 13:
Version = IPNotifyNotification;
case 14: {
LARGE_INTEGER Timeout;
ULONG NotificationCount = 0;
printf("Enter number of requests to queue: ");
if (!scanf("%d", &NotificationCount)) {
break;
}
NotificationCount =
QueueNotifyRouteChange(
FileHandle, Version, NotificationCount
);
for (; NotificationCount; --NotificationCount) {
Timeout.LowPart = 0;
Timeout.HighPart = MINLONG;
NtDelayExecution(TRUE, &Timeout);
}
break;
}
}
}
NtClose(FileHandle);
return 0;
}