예제 #1
0
파일: nmbd.c 프로젝트: eduardok/samba
static void msg_nmbd_send_packet(struct messaging_context *msg,
				 void *private_data,
				 uint32_t msg_type,
				 struct server_id src,
				 DATA_BLOB *data)
{
	struct packet_struct *p = (struct packet_struct *)data->data;
	struct subnet_record *subrec;
	struct sockaddr_storage ss;
	const struct sockaddr_storage *pss;
	const struct in_addr *local_ip;

	DEBUG(10, ("Received send_packet from %u\n", (unsigned int)procid_to_pid(&src)));

	if (data->length != sizeof(struct packet_struct)) {
		DEBUG(2, ("Discarding invalid packet length from %u\n",
			  (unsigned int)procid_to_pid(&src)));
		return;
	}

	if ((p->packet_type != NMB_PACKET) &&
	    (p->packet_type != DGRAM_PACKET)) {
		DEBUG(2, ("Discarding invalid packet type from %u: %d\n",
			  (unsigned int)procid_to_pid(&src), p->packet_type));
		return;
	}

	in_addr_to_sockaddr_storage(&ss, p->ip);
	pss = iface_ip((struct sockaddr *)(void *)&ss);

	if (pss == NULL) {
		DEBUG(2, ("Could not find ip for packet from %u\n",
			  (unsigned int)procid_to_pid(&src)));
		return;
	}

	local_ip = &((const struct sockaddr_in *)pss)->sin_addr;
	subrec = FIRST_SUBNET;

	p->recv_fd = -1;
	p->send_fd = (p->packet_type == NMB_PACKET) ?
		subrec->nmb_sock : subrec->dgram_sock;

	for (subrec = FIRST_SUBNET; subrec != NULL;
	     subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
		if (ip_equal_v4(*local_ip, subrec->myip)) {
			p->send_fd = (p->packet_type == NMB_PACKET) ?
				subrec->nmb_sock : subrec->dgram_sock;
			break;
		}
	}

	if (p->packet_type == DGRAM_PACKET) {
		p->port = 138;
		p->packet.dgram.header.source_ip.s_addr = local_ip->s_addr;
		p->packet.dgram.header.source_port = 138;
	}

	send_packet(p);
}
예제 #2
0
bool is_local_net_v4(struct in_addr from)
{
	struct sockaddr_storage ss;

	in_addr_to_sockaddr_storage(&ss, from);
	return is_local_net((struct sockaddr *)&ss);
}
예제 #3
0
static void sync_child(char *name, int nm_type, 
		       char *workgroup,
		       struct in_addr ip, bool local, bool servers,
		       char *fname)
{
	fstring unix_workgroup;
	struct cli_state *cli;
	uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;
	struct sockaddr_storage ss;
	NTSTATUS status;

	/* W2K DMB's return empty browse lists on port 445. Use 139.
	 * Patch from Andy Levine [email protected].
	 */

	in_addr_to_sockaddr_storage(&ss, ip);

	status = cli_connect_nb(name, &ss, NBT_SMB_PORT, nm_type,
				get_local_machine_name(), SMB_SIGNING_DEFAULT,
				0, &cli);
	if (!NT_STATUS_IS_OK(status)) {
		return;
	}

	status = cli_negprot(cli, PROTOCOL_NT1);
	if (!NT_STATUS_IS_OK(status)) {
		cli_shutdown(cli);
		return;
	}

	if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 1, "", 0,
					       workgroup))) {
		cli_shutdown(cli);
		return;
	}

	if (!NT_STATUS_IS_OK(cli_tree_connect(cli, "IPC$", "IPC", "", 1))) {
		cli_shutdown(cli);
		return;
	}

	/* All the cli_XX functions take UNIX character set. */
	fstrcpy(unix_workgroup, cli->server_domain ? cli->server_domain : workgroup);

	/* Fetch a workgroup list. */
	cli_NetServerEnum(cli, unix_workgroup,
			  local_type|SV_TYPE_DOMAIN_ENUM, 
			  callback, NULL);

	/* Now fetch a server list. */
	if (servers) {
		fstrcpy(unix_workgroup, workgroup);
		cli_NetServerEnum(cli, unix_workgroup, 
				  local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL,
				  callback, NULL);
	}

	cli_shutdown(cli);
}
예제 #4
0
/* IPADDR_INFO_LIST */
static bool AsyncNotify_Move(TALLOC_CTX *mem_ctx, const uint8_t **ptr)
{
	const uint8_t *pos = *ptr;
	uint32_t length   = IVAL(pos,0);
	/* uint32_t reserved = IVAL(pos,4); */
	uint32_t num      = IVAL(pos,8);
	uint32_t n;

	pos += 12;

	for (n=0; n<num; n++) {
		uint32_t flags = IVAL(pos,0);
		struct in_addr ipv4;
		struct in6_addr ipv6;
		struct sockaddr_storage sas4, sas6;
		char *str4, *str6;
		pos += 4;

		ipv4.s_addr = *((const in_addr_t*)pos);
		in_addr_to_sockaddr_storage(&sas4, ipv4);
		str4 = print_canonical_sockaddr(mem_ctx, &sas4);
		pos += 4;

		memcpy(&ipv6.s6_addr, pos, 16);
		in6_addr_to_sockaddr_storage(&sas6, ipv6);
		str6 = print_canonical_sockaddr(mem_ctx, &sas6);
		pos += 16;

		d_printf("Flags 0x%08x", flags);
		if (flags & IPADDR_V4) {
			d_printf(" %s", str4);
		}
		if (flags & IPADDR_V6) {
			d_printf(" %s", str6);
		}
		if (flags & IPADDR_ONLINE) {
			d_printf(" Online");
		}
		if (flags & IPADDR_ONLINE) {
			d_printf(" Offline");
		}
		d_printf("\n");
		TALLOC_FREE(str4);
		TALLOC_FREE(str6);
	}

	if (pos - *ptr == length) {
		*ptr = pos;
		return true;
	}
	return false;
}
예제 #5
0
/* check to see if smbd is running on localhost by trying to open a connection
   then closing it */
bool smbd_running(void)
{
	struct in_addr loopback_ip;
	NTSTATUS status;
	struct cli_state *cli;
	struct sockaddr_storage ss;

	loopback_ip.s_addr = htonl(INADDR_LOOPBACK);
	in_addr_to_sockaddr_storage(&ss, loopback_ip);

	status = cli_connect_nb("localhost", &ss, 0, 0x20, lp_netbios_name(),
				Undefined, 0, &cli);
	if (!NT_STATUS_IS_OK(status)) {
		return false;
	}
	cli_shutdown(cli);
	return True;
}
예제 #6
0
/* check to see if nmbd is running on localhost by looking for a __SAMBA__
   response */
bool nmbd_running(void)
{
	struct in_addr loopback_ip;
	int count;
	struct sockaddr_storage *ss_list;
	struct sockaddr_storage ss;
	NTSTATUS status;

	loopback_ip.s_addr = htonl(INADDR_LOOPBACK);
	in_addr_to_sockaddr_storage(&ss, loopback_ip);

	status = name_query("__SAMBA__", 0,
			    True, True, &ss,
			    talloc_tos(), &ss_list, &count,
			    NULL);
	if (NT_STATUS_IS_OK(status)) {
		TALLOC_FREE(ss_list);
		return True;
	}

	return False;
}
예제 #7
0
파일: nmblookup.c 프로젝트: javierag/samba
/****************************************************************************
  main program
****************************************************************************/
int main(int argc, const char *argv[])
{
	int opt;
	unsigned int lookup_type = 0x0;
	fstring lookup;
	static bool find_master=False;
	static bool lookup_by_ip = False;
	poptContext pc = NULL;
	TALLOC_CTX *frame = talloc_stackframe();
	int rc = 0;

	struct poptOption long_options[] = {
		POPT_AUTOHELP
		{ "broadcast", 'B', POPT_ARG_STRING, NULL, 'B', "Specify address to use for broadcasts", "BROADCAST-ADDRESS" },
		{ "flags", 'f', POPT_ARG_NONE, NULL, 'f', "List the NMB flags returned" },
		{ "unicast", 'U', POPT_ARG_STRING, NULL, 'U', "Specify address to use for unicast" },
		{ "master-browser", 'M', POPT_ARG_NONE, NULL, 'M', "Search for a master browser" },
		{ "recursion", 'R', POPT_ARG_NONE, NULL, 'R', "Set recursion desired in package" },
		{ "status", 'S', POPT_ARG_NONE, NULL, 'S', "Lookup node status as well" },
		{ "translate", 'T', POPT_ARG_NONE, NULL, 'T', "Translate IP addresses into names" },
		{ "root-port", 'r', POPT_ARG_NONE, NULL, 'r', "Use root port 137 (Win95 only replies to this)" },
		{ "lookup-by-ip", 'A', POPT_ARG_NONE, NULL, 'A', "Do a node status on <name> as an IP Address" },
		POPT_COMMON_SAMBA
		POPT_COMMON_CONNECTION
		{ 0, 0, 0, 0 }
	};

	*lookup = 0;

	load_case_tables();

	setup_logging(argv[0], DEBUG_STDOUT);

	pc = poptGetContext("nmblookup", argc, argv,
			long_options, POPT_CONTEXT_KEEP_FIRST);

	poptSetOtherOptionHelp(pc, "<NODE> ...");

	while ((opt = poptGetNextOpt(pc)) != -1) {
		switch (opt) {
		case 'f':
			give_flags = true;
			break;
		case 'M':
			find_master = true;
			break;
		case 'R':
			recursion_desired = true;
			break;
		case 'S':
			find_status = true;
			break;
		case 'r':
			RootPort = true;
			break;
		case 'A':
			lookup_by_ip = true;
			break;
		case 'B':
			if (interpret_string_addr(&bcast_addr,
					poptGetOptArg(pc),
					NI_NUMERICHOST)) {
				got_bcast = True;
				use_bcast = True;
			}
			break;
		case 'U':
			if (interpret_string_addr(&bcast_addr,
					poptGetOptArg(pc),
					0)) {
				got_bcast = True;
				use_bcast = False;
			}
			break;
		case 'T':
			translate_addresses = !translate_addresses;
			break;
		}
	}

	poptGetArg(pc); /* Remove argv[0] */

	if(!poptPeekArg(pc)) {
		poptPrintUsage(pc, stderr, 0);
		rc = 1;
		goto out;
	}

	if (!lp_load_global(get_dyn_CONFIGFILE())) {
		fprintf(stderr, "Can't load %s - run testparm to debug it\n",
				get_dyn_CONFIGFILE());
	}

	load_interfaces();
	if (!open_sockets()) {
		rc = 1;
		goto out;
	}

	while(poptPeekArg(pc)) {
		char *p;
		struct in_addr ip;

		fstrcpy(lookup,poptGetArg(pc));

		if(lookup_by_ip) {
			struct sockaddr_storage ss;
			ip = interpret_addr2(lookup);
			in_addr_to_sockaddr_storage(&ss, ip);
			fstrcpy(lookup,"*");
			if (!do_node_status(lookup, lookup_type, &ss)) {
				rc = 1;
			}
			continue;
		}

		if (find_master) {
			if (*lookup == '-') {
				fstrcpy(lookup,"\01\02__MSBROWSE__\02");
				lookup_type = 1;
			} else {
				lookup_type = 0x1d;
			}
		}

		p = strchr_m(lookup,'#');
		if (p) {
			*p = '\0';
			sscanf(++p,"%x",&lookup_type);
		}

		if (!query_one(lookup, lookup_type)) {
			rc = 1;
			d_printf( "name_query failed to find name %s", lookup );
			if( 0 != lookup_type ) {
				d_printf( "#%02x", lookup_type );
			}
			d_printf( "\n" );
		}
	}

out:
	poptFreeContext(pc);
	TALLOC_FREE(frame);
	return rc;
}
예제 #8
0
static struct subnet_record *make_subnet(const char *name, enum subnet_type type,
					 struct in_addr myip, struct in_addr bcast_ip, 
					 struct in_addr mask_ip)
{
	struct subnet_record *subrec = NULL;
	int nmb_sock = -1;
	int dgram_sock = -1;
	int nmb_bcast = -1;
	int dgram_bcast = -1;
	bool bind_bcast = lp_nmbd_bind_explicit_broadcast();

	/* Check if we are creating a non broadcast subnet - if so don't create
		sockets.  */

	if (type == NORMAL_SUBNET) {
		struct sockaddr_storage ss;
		struct sockaddr_storage ss_bcast;

		in_addr_to_sockaddr_storage(&ss, myip);
		in_addr_to_sockaddr_storage(&ss_bcast, bcast_ip);

		/*
		 * Attempt to open the sockets on port 137/138 for this interface
		 * and bind them.
		 * Fail the subnet creation if this fails.
		 */

		nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,
					  0, &ss, true);
		if (nmb_sock == -1) {
			DEBUG(0,   ("nmbd_subnetdb:make_subnet()\n"));
			DEBUGADD(0,("  Failed to open nmb socket on interface %s ",
				    inet_ntoa(myip)));
			DEBUGADD(0,("for port %d.  ", global_nmb_port));
			DEBUGADD(0,("Error was %s\n", strerror(errno)));
			goto failed;
		}
		set_socket_options(nmb_sock,"SO_BROADCAST");
		set_blocking(nmb_sock, false);

		if (bind_bcast) {
			nmb_bcast = open_socket_in(SOCK_DGRAM, global_nmb_port,
						   0, &ss_bcast, true);
			if (nmb_bcast == -1) {
				DEBUG(0,   ("nmbd_subnetdb:make_subnet()\n"));
				DEBUGADD(0,("  Failed to open nmb bcast socket on interface %s ",
					    inet_ntoa(bcast_ip)));
				DEBUGADD(0,("for port %d.  ", global_nmb_port));
				DEBUGADD(0,("Error was %s\n", strerror(errno)));
				goto failed;
			}
			set_socket_options(nmb_bcast, "SO_BROADCAST");
			set_blocking(nmb_bcast, false);
		}

		dgram_sock = open_socket_in(SOCK_DGRAM, DGRAM_PORT,
					    3, &ss, true);
		if (dgram_sock == -1) {
			DEBUG(0,   ("nmbd_subnetdb:make_subnet()\n"));
			DEBUGADD(0,("  Failed to open dgram socket on interface %s ",
				    inet_ntoa(myip)));
			DEBUGADD(0,("for port %d.  ", DGRAM_PORT));
			DEBUGADD(0,("Error was %s\n", strerror(errno)));
			goto failed;
		}
		set_socket_options(dgram_sock, "SO_BROADCAST");
		set_blocking(dgram_sock, false);

		if (bind_bcast) {
			dgram_bcast = open_socket_in(SOCK_DGRAM, DGRAM_PORT,
						     3, &ss_bcast, true);
			if (dgram_bcast == -1) {
				DEBUG(0,   ("nmbd_subnetdb:make_subnet()\n"));
				DEBUGADD(0,("  Failed to open dgram bcast socket on interface %s ",
					    inet_ntoa(bcast_ip)));
				DEBUGADD(0,("for port %d.  ", DGRAM_PORT));
				DEBUGADD(0,("Error was %s\n", strerror(errno)));
				goto failed;
			}
			set_socket_options(dgram_bcast, "SO_BROADCAST");
			set_blocking(dgram_bcast, false);
		}
	}

	subrec = SMB_MALLOC_P(struct subnet_record);
	if (!subrec) {
		DEBUG(0,("make_subnet: malloc fail !\n"));
		goto failed;
	}
  
	ZERO_STRUCTP(subrec);

	if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) {
		DEBUG(0,("make_subnet: malloc fail for subnet name !\n"));
		goto failed;
	}

	DEBUG(2, ("making subnet name:%s ", name ));
	DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip)));
	DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip)));
 
	subrec->namelist_changed = False;
	subrec->work_changed = False;
 
	subrec->bcast_ip = bcast_ip;
	subrec->mask_ip  = mask_ip;
	subrec->myip = myip;
	subrec->type = type;
	subrec->nmb_sock = nmb_sock;
	subrec->nmb_bcast = nmb_bcast;
	subrec->dgram_sock = dgram_sock;
	subrec->dgram_bcast = dgram_bcast;

	return subrec;

failed:
	SAFE_FREE(subrec);
	if (nmb_sock != -1) {
		close(nmb_sock);
	}
	if (nmb_bcast != -1) {
		close(nmb_bcast);
	}
	if (dgram_sock != -1) {
		close(dgram_sock);
	}
	if (dgram_bcast != -1) {
		close(dgram_bcast);
	}
	return NULL;
}
예제 #9
0
static void sync_child(char *name, int nm_type, 
		       char *workgroup,
		       struct in_addr ip, bool local, bool servers,
		       char *fname)
{
	fstring unix_workgroup;
	struct cli_state *cli;
	uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;
	struct nmb_name called, calling;
	struct sockaddr_storage ss;
	NTSTATUS status;

	/* W2K DMB's return empty browse lists on port 445. Use 139.
	 * Patch from Andy Levine [email protected].
	 */

	cli = cli_initialise();
	if (!cli) {
		return;
	}

	if (!cli_set_port(cli, 139)) {
		cli_shutdown(cli);
		return;
	}

	in_addr_to_sockaddr_storage(&ss, ip);
	status = cli_connect(cli, name, &ss);
	if (!NT_STATUS_IS_OK(status)) {
		cli_shutdown(cli);
		return;
	}

	make_nmb_name(&calling, get_local_machine_name(), 0x0);
	make_nmb_name(&called , name, nm_type);

	if (!cli_session_request(cli, &calling, &called)) {
		cli_shutdown(cli);
		return;
	}

	if (!cli_negprot(cli)) {
		cli_shutdown(cli);
		return;
	}

	if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 1, "", 0,
					       workgroup))) {
		cli_shutdown(cli);
		return;
	}

	if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) {
		cli_shutdown(cli);
		return;
	}

	/* All the cli_XX functions take UNIX character set. */
	fstrcpy(unix_workgroup, cli->server_domain ? cli->server_domain : workgroup);

	/* Fetch a workgroup list. */
	cli_NetServerEnum(cli, unix_workgroup,
			  local_type|SV_TYPE_DOMAIN_ENUM, 
			  callback, NULL);
	
	/* Now fetch a server list. */
	if (servers) {
		fstrcpy(unix_workgroup, workgroup);
		cli_NetServerEnum(cli, unix_workgroup, 
				  local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL,
				  callback, NULL);
	}
	
	cli_shutdown(cli);
}
예제 #10
0
int vscan_send_warning_message(const char *filename, const char *virname, const char *ipaddr) {
    struct in_addr ip;
    struct sockaddr_storage ss;

        struct nmb_name called, calling;
	pstring myname;
	pstring message;
	pstring shortfilename;
	char* lastslash;

	static pstring lastfile;
	static pstring lastip;

	#if SAMBA_VERSION_MAJOR==3
	fstrcpy(remote_machine, get_remote_machine_name());
	DEBUG(5, ("remote machine is: %s\n", remote_machine));
	#endif

	/* Only notify once for a given virus/ip combo - otherwise the
	 * scanner will go crazy reaccessing the file and sending
	 * messages once the user hits the "okay" button */
	if (strncmp(lastfile,filename,sizeof(pstring)) == 0) {
		if (strncmp(lastip,ipaddr,sizeof(pstring)) == 0) {
			DEBUG(5,("Both IP and Filename are the same, not notifying\n"));
			return 0;
		}
	}

	ZERO_ARRAY(lastfile);
	ZERO_ARRAY(lastip);
	pstrcpy(lastfile,filename);
	pstrcpy(lastip,ipaddr);

	ZERO_ARRAY(myname);
	pstrcpy(myname,myhostname());

	ZERO_ARRAY(username);
	/* could make this configurable */
	snprintf(username,sizeof(pstring)-1,"%s VIRUS SCANNER",myname);

	/* We need to get the real ip structure from the ip string
	 * is this info already available somewhere else in samba? */
       	zero_ip_v4(&ip);
	if (inet_aton(ipaddr,&ip) == 0) {
               	DEBUG(5,("Cannot resolve ip address %s\n", ipaddr));
               	return 1;
	}
    in_addr_to_sockaddr_storage(&ss, ip);


       	make_nmb_name(&calling, myname, 0x0);
       	make_nmb_name(&called , remote_machine, name_type);

	 if (!(cli=cli_initialise())) {
               	DEBUG(5,("Connection to %s failed\n", remote_machine));
               	return 1;
       	}
        cli_set_port(cli, port);
     if (!NT_STATUS_IS_OK(cli_connect(cli, remote_machine, &ss))) {
               	DEBUG(5,("Connection to %s failed\n", remote_machine));
               	return 1;
    }

       	if (!cli_session_request(cli, &calling, &called)) {
               	DEBUG(5,("session request failed\n"));
               	cli_shutdown(cli);
               	return 1;
       	}

	ZERO_ARRAY(shortfilename);
	/* we don't want the entire filename, otherwise the message service may choke
	 * so we chop off the path up to the very last forward-slash
	 * assumption: unix-style pathnames in filename (don't know if there's a
	 * portable file-separator variable... */
	lastslash = strrchr(filename,'/');
	if (lastslash != NULL && lastslash != filename) {
		pstrcpy(shortfilename,lastslash+1);
	} else {
		pstrcpy(shortfilename,filename);
	}

	ZERO_ARRAY(message);
	/* could make the message configurable and language specific? */
	snprintf(message,sizeof(pstring)-1,
		"%s IS INFECTED WITH VIRUS  %s.\r\n\r\nAccess will be denied.\r\nPlease contact your system administrator",
		shortfilename, virname);

	/* actually send the message... */
       	send_message(message);

       	cli_shutdown(cli);
	
        return 0;
}
예제 #11
0
static bool query_one(const char *lookup, unsigned int lookup_type)
{
	int j, count, flags = 0;
	struct sockaddr_storage *ip_list=NULL;

	if (got_bcast) {
		char addr[INET6_ADDRSTRLEN];
		print_sockaddr(addr, sizeof(addr), &bcast_addr);
		d_printf("querying %s on %s\n", lookup, addr);
		ip_list = name_query(ServerFD,lookup,lookup_type,use_bcast,
				     use_bcast?true:recursion_desired,
				     &bcast_addr, &count, &flags, NULL);
	} else {
		const struct in_addr *bcast;
		for (j=iface_count() - 1;
		     !ip_list && j >= 0;
		     j--) {
			char addr[INET6_ADDRSTRLEN];
			struct sockaddr_storage bcast_ss;

			bcast = iface_n_bcast_v4(j);
			if (!bcast) {
				continue;
			}
			in_addr_to_sockaddr_storage(&bcast_ss, *bcast);
			print_sockaddr(addr, sizeof(addr), &bcast_ss);
			d_printf("querying %s on %s\n",
			       lookup, addr);
			ip_list = name_query(ServerFD,lookup,lookup_type,
					     use_bcast,
					     use_bcast?True:recursion_desired,
					     &bcast_ss,&count, &flags, NULL);
		}
	}

	if (!ip_list) {
		return false;
	}

	if (give_flags) {
		d_printf("Flags: %s\n", query_flags(flags));
	}

	for (j=0;j<count;j++) {
		char addr[INET6_ADDRSTRLEN];
		if (translate_addresses) {
			char h_name[MAX_DNS_NAME_LENGTH];
			h_name[0] = '\0';
			if (sys_getnameinfo((const struct sockaddr *)&ip_list[j],
					sizeof(struct sockaddr_storage),
					h_name, sizeof(h_name),
					NULL, 0,
					NI_NAMEREQD)) {
				continue;
			}
			d_printf("%s, ", h_name);
		}
		print_sockaddr(addr, sizeof(addr), &ip_list[j]);
		d_printf("%s %s<%02x>\n", addr,lookup, lookup_type);
		/* We can only do find_status if the ip address returned
		   was valid - ie. name_query returned true.
		 */
		if (find_status) {
			do_node_status(ServerFD, lookup,
					lookup_type, &ip_list[j]);
		}
	}

	free(ip_list);

	return (ip_list != NULL);
}
예제 #12
0
bool ismyip_v4(struct in_addr ip)
{
	struct sockaddr_storage ss;
	in_addr_to_sockaddr_storage(&ss, ip);
	return ismyaddr((struct sockaddr *)&ss);
}