initial commit
This commit is contained in:
commit
9d20827c46
2469 changed files with 470994 additions and 0 deletions
85
iris-legacy/iris/irisnet/jdns/README
Normal file
85
iris-legacy/iris/irisnet/jdns/README
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
JDNS
|
||||
----
|
||||
Date: October 1st, 2005
|
||||
Author: Justin Karneges <justin@affinix.com>
|
||||
|
||||
JDNS is a simple DNS implementation that can perform normal DNS queries
|
||||
of any record type (notably SRV), as well as Multicast DNS queries and
|
||||
advertising. Multicast support is based on Jeremie Miller's "mdnsd"
|
||||
implementation.
|
||||
|
||||
For maximum flexibility, JDNS is written in C with no direct dependencies,
|
||||
and is licensed under the MIT license. Your application must supply
|
||||
functionality to JDNS, such as UDP sending/receiving, via callbacks.
|
||||
|
||||
For Qt users there is a wrapper available called QJDns. jdns.pri can
|
||||
be used to include everything into a qmake project. jdns.pro will build
|
||||
the sample Qt-based commandline tool 'jdns'.
|
||||
|
||||
Features:
|
||||
- DNS client "stub" resolver
|
||||
- Can fetch any record type, but provides handy decoding for many
|
||||
known types: A, AAAA, SRV, MX, TXT, etc.
|
||||
- Performs retries, caching/expiration, and CNAME following
|
||||
- Algorithm logic adapted from Q3Dns
|
||||
- Multicast queries
|
||||
- Multicast advertising
|
||||
|
||||
Why?
|
||||
- Trolltech is phasing out the Qt DNS implementation, which in Qt 4 has
|
||||
been relegated to the Qt3Support module. A replacement was desired.
|
||||
|
||||
- While there are many DNS libraries available, at the time of this
|
||||
writing it was (and still may be) hard to find one that satisfies
|
||||
three essential conditions: cross-platform friendliness (and this
|
||||
includes Windows 9x!), the ability to integrate into existing
|
||||
eventloops, sensible licensing (ie, not GPL).
|
||||
|
||||
How to use:
|
||||
- Prepare callbacks and call jdns_session_new()
|
||||
- Call jdns_init_unicast() or jdns_init_multicast(), depending on
|
||||
if you want regular or multicast DNS. If you want both kinds, you
|
||||
can always make two sessions.
|
||||
- Make queries and have fun
|
||||
- Call jdns_step() at the right times to advance JDNS processing
|
||||
|
||||
What is left to you:
|
||||
- The callback functions, obviously.
|
||||
- Querying for several "qualified" names. Here is what Q3Dns does:
|
||||
Query for name as provided
|
||||
Query for name + '.domain' (for every domain the computer is in)
|
||||
- Detecting for '.local' in a name to be queried, and using that
|
||||
to decide whether to query via Multicast or normal DNS.
|
||||
- Recognition of IP addresses. If you want an IP address to resolve
|
||||
to itself, then do that yourself. Passing an IP address as a DNS
|
||||
name to JDNS won't work (especially since it wouldn't make any
|
||||
sense in some contexts, like SRV).
|
||||
- Recognition of known hosts. If you want this, compare inputs against
|
||||
jdns_system_dnsparams().
|
||||
- For zeroconf/Bonjour, keep in mind that JDNS only provides Multicast
|
||||
DNS capability. DNS-SD and any higher layers would be your job.
|
||||
|
||||
Using a custom DNS implementation has the drawback that it is difficult
|
||||
to take advantage of platform-specific features (for example, an OS-wide
|
||||
DNS cache or LDAP integration).
|
||||
|
||||
An application strategy for normal DNS should probably be:
|
||||
- If an A or AAAA record is desired, use a native lookup.
|
||||
- Else, if the platform has advanced DNS features already (ie,
|
||||
res_query), use those.
|
||||
- Else, use JDNS.
|
||||
|
||||
However, it may not be a bad idea at first to use JDNS for all occasions,
|
||||
so that it can be debugged.
|
||||
|
||||
For Multicast DNS, awareness of the platform is doubly important. There
|
||||
should only be one Multicast DNS "Responder" per computer, and using JDNS
|
||||
at the same time could result in a conflict.
|
||||
|
||||
An application strategy for Multicast DNS should be:
|
||||
- If the platform has a Multicast DNS daemon installed already, use
|
||||
it somehow.
|
||||
- Else, use JDNS.
|
||||
|
||||
Have fun!
|
||||
|
||||
1
iris-legacy/iris/irisnet/jdns/TODO
Normal file
1
iris-legacy/iris/irisnet/jdns/TODO
Normal file
|
|
@ -0,0 +1 @@
|
|||
(nothing)
|
||||
3176
iris-legacy/iris/irisnet/jdns/jdns.c
Normal file
3176
iris-legacy/iris/irisnet/jdns/jdns.c
Normal file
File diff suppressed because it is too large
Load diff
490
iris-legacy/iris/irisnet/jdns/jdns.h
Normal file
490
iris-legacy/iris/irisnet/jdns/jdns.h
Normal file
|
|
@ -0,0 +1,490 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef JDNS_H
|
||||
#define JDNS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*jdns_object_dtor_func)(void *);
|
||||
typedef void *(*jdns_object_cctor_func)(const void *);
|
||||
|
||||
#define JDNS_OBJECT \
|
||||
jdns_object_dtor_func dtor; \
|
||||
jdns_object_cctor_func cctor;
|
||||
|
||||
#define JDNS_OBJECT_NEW(name) \
|
||||
(name##_t *)jdns_object_new(sizeof(name##_t), \
|
||||
(jdns_object_dtor_func)name##_delete, \
|
||||
(jdns_object_cctor_func)name##_copy);
|
||||
|
||||
typedef struct jdns_object
|
||||
{
|
||||
JDNS_OBJECT
|
||||
} jdns_object_t;
|
||||
|
||||
void *jdns_object_new(int size, void (*dtor)(void *),
|
||||
void *(*cctor)(const void *));
|
||||
void *jdns_object_copy(const void *a);
|
||||
void jdns_object_delete(void *a);
|
||||
void jdns_object_free(void *a);
|
||||
|
||||
#define JDNS_LIST_DECLARE(name) \
|
||||
JDNS_OBJECT \
|
||||
int count; \
|
||||
name##_t **item;
|
||||
|
||||
typedef struct jdns_list
|
||||
{
|
||||
JDNS_OBJECT
|
||||
int count;
|
||||
void **item;
|
||||
int valueList;
|
||||
int autoDelete;
|
||||
} jdns_list_t;
|
||||
|
||||
jdns_list_t *jdns_list_new();
|
||||
jdns_list_t *jdns_list_copy(const jdns_list_t *a);
|
||||
void jdns_list_delete(jdns_list_t *a);
|
||||
void jdns_list_clear(jdns_list_t *a);
|
||||
void jdns_list_insert(jdns_list_t *a, void *item, int pos);
|
||||
void jdns_list_insert_value(jdns_list_t *a, const void *item, int pos);
|
||||
void jdns_list_remove(jdns_list_t *a, void *item);
|
||||
void jdns_list_remove_at(jdns_list_t *a, int pos);
|
||||
|
||||
typedef struct jdns_string
|
||||
{
|
||||
JDNS_OBJECT
|
||||
unsigned char *data;
|
||||
int size;
|
||||
} jdns_string_t;
|
||||
|
||||
jdns_string_t *jdns_string_new();
|
||||
jdns_string_t *jdns_string_copy(const jdns_string_t *s);
|
||||
void jdns_string_delete(jdns_string_t *s);
|
||||
void jdns_string_set(jdns_string_t *s, const unsigned char *str,
|
||||
int str_len);
|
||||
void jdns_string_set_cstr(jdns_string_t *s, const char *str);
|
||||
|
||||
// overlays jdns_list
|
||||
typedef struct jdns_stringlist
|
||||
{
|
||||
JDNS_OBJECT
|
||||
int count;
|
||||
jdns_string_t **item;
|
||||
} jdns_stringlist_t;
|
||||
|
||||
jdns_stringlist_t *jdns_stringlist_new();
|
||||
jdns_stringlist_t *jdns_stringlist_copy(const jdns_stringlist_t *a);
|
||||
void jdns_stringlist_delete(jdns_stringlist_t *a);
|
||||
void jdns_stringlist_append(jdns_stringlist_t *a, const jdns_string_t *str);
|
||||
|
||||
typedef struct jdns_address
|
||||
{
|
||||
int isIpv6;
|
||||
union
|
||||
{
|
||||
unsigned long int v4;
|
||||
unsigned char *v6; // 16 bytes
|
||||
} addr;
|
||||
char *c_str;
|
||||
} jdns_address_t;
|
||||
|
||||
jdns_address_t *jdns_address_new();
|
||||
jdns_address_t *jdns_address_copy(const jdns_address_t *a);
|
||||
void jdns_address_delete(jdns_address_t *a);
|
||||
void jdns_address_set_ipv4(jdns_address_t *a, unsigned long int ipv4);
|
||||
void jdns_address_set_ipv6(jdns_address_t *a, const unsigned char *ipv6);
|
||||
// return 1 if string was ok, else 0. Note: IPv4 addresses only!
|
||||
int jdns_address_set_cstr(jdns_address_t *a, const char *str);
|
||||
// return 1 if the same, else 0
|
||||
int jdns_address_cmp(const jdns_address_t *a, const jdns_address_t *b);
|
||||
|
||||
// convenient predefined addresses/ports
|
||||
#define JDNS_UNICAST_PORT 53
|
||||
#define JDNS_MULTICAST_PORT 5353
|
||||
jdns_address_t *jdns_address_multicast4_new(); // 224.0.0.251
|
||||
jdns_address_t *jdns_address_multicast6_new(); // FF02::FB
|
||||
|
||||
typedef struct jdns_server
|
||||
{
|
||||
unsigned char *name;
|
||||
int port; // SRV only
|
||||
int priority;
|
||||
int weight; // SRV only
|
||||
} jdns_server_t;
|
||||
|
||||
jdns_server_t *jdns_server_new();
|
||||
jdns_server_t *jdns_server_copy(const jdns_server_t *s);
|
||||
void jdns_server_delete(jdns_server_t *s);
|
||||
void jdns_server_set_name(jdns_server_t *s, const unsigned char *name);
|
||||
|
||||
typedef struct jdns_nameserver
|
||||
{
|
||||
jdns_address_t *address;
|
||||
int port;
|
||||
} jdns_nameserver_t;
|
||||
|
||||
jdns_nameserver_t *jdns_nameserver_new();
|
||||
jdns_nameserver_t *jdns_nameserver_copy(const jdns_nameserver_t *a);
|
||||
void jdns_nameserver_delete(jdns_nameserver_t *a);
|
||||
void jdns_nameserver_set(jdns_nameserver_t *a, const jdns_address_t *addr,
|
||||
int port);
|
||||
|
||||
typedef struct jdns_nameserverlist
|
||||
{
|
||||
int count;
|
||||
jdns_nameserver_t **item;
|
||||
} jdns_nameserverlist_t;
|
||||
|
||||
jdns_nameserverlist_t *jdns_nameserverlist_new();
|
||||
jdns_nameserverlist_t *jdns_nameserverlist_copy(
|
||||
const jdns_nameserverlist_t *a);
|
||||
void jdns_nameserverlist_delete(jdns_nameserverlist_t *a);
|
||||
void jdns_nameserverlist_append(jdns_nameserverlist_t *a,
|
||||
const jdns_address_t *addr, int port);
|
||||
|
||||
typedef struct jdns_dnshost
|
||||
{
|
||||
jdns_string_t *name;
|
||||
jdns_address_t *address;
|
||||
} jdns_dnshost_t;
|
||||
|
||||
typedef struct jdns_dnshostlist
|
||||
{
|
||||
int count;
|
||||
jdns_dnshost_t **item;
|
||||
} jdns_dnshostlist_t;
|
||||
|
||||
typedef struct jdns_dnsparams
|
||||
{
|
||||
jdns_nameserverlist_t *nameservers;
|
||||
jdns_stringlist_t *domains;
|
||||
jdns_dnshostlist_t *hosts;
|
||||
} jdns_dnsparams_t;
|
||||
|
||||
jdns_dnsparams_t *jdns_dnsparams_new();
|
||||
jdns_dnsparams_t *jdns_dnsparams_copy(jdns_dnsparams_t *a);
|
||||
void jdns_dnsparams_delete(jdns_dnsparams_t *a);
|
||||
void jdns_dnsparams_append_nameserver(jdns_dnsparams_t *a,
|
||||
const jdns_address_t *addr, int port);
|
||||
void jdns_dnsparams_append_domain(jdns_dnsparams_t *a,
|
||||
const jdns_string_t *domain);
|
||||
void jdns_dnsparams_append_host(jdns_dnsparams_t *a,
|
||||
const jdns_string_t *name, const jdns_address_t *address);
|
||||
|
||||
#define JDNS_RTYPE_A 1
|
||||
#define JDNS_RTYPE_AAAA 28
|
||||
#define JDNS_RTYPE_MX 15
|
||||
#define JDNS_RTYPE_SRV 33
|
||||
#define JDNS_RTYPE_CNAME 5
|
||||
#define JDNS_RTYPE_PTR 12
|
||||
#define JDNS_RTYPE_TXT 16
|
||||
#define JDNS_RTYPE_HINFO 13
|
||||
#define JDNS_RTYPE_NS 2
|
||||
#define JDNS_RTYPE_ANY 255
|
||||
|
||||
typedef struct jdns_rr
|
||||
{
|
||||
unsigned char *owner;
|
||||
int ttl;
|
||||
int type;
|
||||
int qclass;
|
||||
int rdlength;
|
||||
unsigned char *rdata;
|
||||
int haveKnown;
|
||||
|
||||
union
|
||||
{
|
||||
jdns_address_t *address; // for A, AAAA
|
||||
jdns_server_t *server; // for MX, SRV
|
||||
unsigned char *name; // for CNAME, PTR, NS
|
||||
jdns_stringlist_t *texts; // for TXT
|
||||
struct
|
||||
{
|
||||
jdns_string_t *cpu;
|
||||
jdns_string_t *os;
|
||||
} hinfo; // for HINFO
|
||||
} data;
|
||||
} jdns_rr_t;
|
||||
|
||||
jdns_rr_t *jdns_rr_new();
|
||||
jdns_rr_t *jdns_rr_copy(const jdns_rr_t *r);
|
||||
void jdns_rr_delete(jdns_rr_t *r);
|
||||
void jdns_rr_set_owner(jdns_rr_t *r, const unsigned char *name);
|
||||
void jdns_rr_set_record(jdns_rr_t *r, int type, const unsigned char *rdata,
|
||||
int rdlength);
|
||||
void jdns_rr_set_A(jdns_rr_t *r, const jdns_address_t *address);
|
||||
void jdns_rr_set_AAAA(jdns_rr_t *r, const jdns_address_t *address);
|
||||
void jdns_rr_set_MX(jdns_rr_t *r, const unsigned char *name, int priority);
|
||||
void jdns_rr_set_SRV(jdns_rr_t *r, const unsigned char *name, int port,
|
||||
int priority, int weight);
|
||||
void jdns_rr_set_CNAME(jdns_rr_t *r, const unsigned char *name);
|
||||
void jdns_rr_set_PTR(jdns_rr_t *r, const unsigned char *name);
|
||||
void jdns_rr_set_TXT(jdns_rr_t *r, const jdns_stringlist_t *texts);
|
||||
void jdns_rr_set_HINFO(jdns_rr_t *r, const jdns_string_t *cpu,
|
||||
const jdns_string_t *os);
|
||||
void jdns_rr_set_NS(jdns_rr_t *r, const unsigned char *name);
|
||||
// note: only works on known types
|
||||
int jdns_rr_verify(const jdns_rr_t *r);
|
||||
|
||||
typedef struct jdns_response
|
||||
{
|
||||
int answerCount;
|
||||
jdns_rr_t **answerRecords;
|
||||
int authorityCount;
|
||||
jdns_rr_t **authorityRecords;
|
||||
int additionalCount;
|
||||
jdns_rr_t **additionalRecords;
|
||||
} jdns_response_t;
|
||||
|
||||
jdns_response_t *jdns_response_new();
|
||||
jdns_response_t *jdns_response_copy(const jdns_response_t *r);
|
||||
void jdns_response_delete(jdns_response_t *r);
|
||||
void jdns_response_append_answer(jdns_response_t *r, const jdns_rr_t *rr);
|
||||
void jdns_response_append_authority(jdns_response_t *r, const jdns_rr_t *rr);
|
||||
void jdns_response_append_additional(jdns_response_t *r,
|
||||
const jdns_rr_t *rr);
|
||||
|
||||
#define JDNS_PUBLISH_SHARED 0x0001
|
||||
#define JDNS_PUBLISH_UNIQUE 0x0002
|
||||
|
||||
#define JDNS_STEP_TIMER 0x0001
|
||||
#define JDNS_STEP_HANDLE 0x0002
|
||||
|
||||
#define JDNS_EVENT_RESPONSE 0x0001
|
||||
#define JDNS_EVENT_PUBLISH 0x0002
|
||||
#define JDNS_EVENT_SHUTDOWN 0x0003
|
||||
|
||||
#define JDNS_STATUS_SUCCESS 0x0001
|
||||
#define JDNS_STATUS_NXDOMAIN 0x0002
|
||||
#define JDNS_STATUS_ERROR 0x0003
|
||||
#define JDNS_STATUS_TIMEOUT 0x0004
|
||||
#define JDNS_STATUS_CONFLICT 0x0005
|
||||
|
||||
typedef struct jdns_session jdns_session_t;
|
||||
|
||||
typedef struct jdns_callbacks
|
||||
{
|
||||
void *app; // user-supplied context
|
||||
|
||||
// time_now:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// return: milliseconds since session started
|
||||
int (*time_now)(jdns_session_t *s, void *app);
|
||||
|
||||
// rand_int:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// return: random integer between 0-65535
|
||||
int (*rand_int)(jdns_session_t *s, void *app);
|
||||
|
||||
// debug_line:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// str: a line of debug text
|
||||
// return: nothing
|
||||
void (*debug_line)(jdns_session_t *s, void *app, const char *str);
|
||||
|
||||
// udp_bind:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// addr: ip address of interface to bind to. 0 for all
|
||||
// port: port of interface to bind to. 0 for any
|
||||
// maddr: multicast address. 0 if not using multicast
|
||||
// return: handle (>0) of bound socket, or 0 on error
|
||||
// note: for multicast, the following must be done:
|
||||
// use SO_REUSEPORT to share with other mdns programs
|
||||
// use IP_ADD_MEMBERSHIP to associate addr and maddr
|
||||
// set IP_MULTICAST_TTL to 255
|
||||
int (*udp_bind)(jdns_session_t *s, void *app,
|
||||
const jdns_address_t *addr, int port,
|
||||
const jdns_address_t *maddr);
|
||||
|
||||
// udp_unbind:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// handle: handle of socket obtained with udp_bind
|
||||
// return: nothing
|
||||
void (*udp_unbind)(jdns_session_t *s, void *app, int handle);
|
||||
|
||||
// udp_read:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// handle: handle of socket obtained with udp_bind
|
||||
// addr: store ip address of sender
|
||||
// port: store port of sender
|
||||
// buf: store packet content
|
||||
// bufsize: value contains max size, to be changed to real size
|
||||
// return: 1 if packet read, 0 if none available
|
||||
int (*udp_read)(jdns_session_t *s, void *app, int handle,
|
||||
jdns_address_t *addr, int *port, unsigned char *buf,
|
||||
int *bufsize);
|
||||
|
||||
// udp_write:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// handle: handle of socket obtained with udp_bind
|
||||
// addr: ip address of recipient
|
||||
// port: port of recipient
|
||||
// buf: packet content
|
||||
// bufsize: size of packet
|
||||
// return: 1 if packet taken for writing, 0 if this is a bad time
|
||||
int (*udp_write)(jdns_session_t *s, void *app, int handle,
|
||||
const jdns_address_t *addr, int port, unsigned char *buf,
|
||||
int bufsize);
|
||||
} jdns_callbacks_t;
|
||||
|
||||
typedef struct jdns_event
|
||||
{
|
||||
int type; // JDNS_EVENT
|
||||
int id; // query id or publish id
|
||||
|
||||
// for query, this can be SUCCESS, NXDOMAIN, ERROR, or TIMEOUT
|
||||
// for publish, this can be SUCCESS, ERROR, or CONFLICT
|
||||
int status;
|
||||
|
||||
// for query
|
||||
jdns_response_t *response;
|
||||
} jdns_event_t;
|
||||
|
||||
void jdns_event_delete(jdns_event_t *e);
|
||||
|
||||
// jdns_session_new:
|
||||
// callbacks: the struct of callbacks
|
||||
// return: newly allocated session
|
||||
jdns_session_t *jdns_session_new(jdns_callbacks_t *callbacks);
|
||||
|
||||
// jdns_session_delete:
|
||||
// s: session to free
|
||||
// return: nothing
|
||||
void jdns_session_delete(jdns_session_t *s);
|
||||
|
||||
// jdns_init_unicast:
|
||||
// s: session
|
||||
// addr: ip address of interface to bind to. NULL for all
|
||||
// port: port of interface to bind to. 0 for any
|
||||
// return: 1 on success, 0 on failure
|
||||
int jdns_init_unicast(jdns_session_t *s, const jdns_address_t *addr,
|
||||
int port);
|
||||
|
||||
// jdns_init_multicast:
|
||||
// s: session
|
||||
// addr: ip address of interface to bind to. NULL for all
|
||||
// port: port of interface to bind to. 0 for any
|
||||
// addr: multicast address to associate with. cannot be NULL
|
||||
// return: 1 on success, 0 on failure
|
||||
int jdns_init_multicast(jdns_session_t *s, const jdns_address_t *addr,
|
||||
int port, const jdns_address_t *maddr);
|
||||
|
||||
// jdns_shutdown:
|
||||
// s: session
|
||||
// return: nothing
|
||||
void jdns_shutdown(jdns_session_t *s);
|
||||
|
||||
// jdns_set_nameservers:
|
||||
// s: session
|
||||
// nslist: list of nameservers
|
||||
// return nothing
|
||||
void jdns_set_nameservers(jdns_session_t *s,
|
||||
const jdns_nameserverlist_t *nslist);
|
||||
|
||||
// jdns_probe:
|
||||
// s: session
|
||||
// return: nothing
|
||||
void jdns_probe(jdns_session_t *s);
|
||||
|
||||
// jdns_query:
|
||||
// s: session
|
||||
// name: the name to look up
|
||||
// rtype: the record type
|
||||
// return: id of this operation
|
||||
int jdns_query(jdns_session_t *s, const unsigned char *name, int rtype);
|
||||
|
||||
// jdns_cancel_query:
|
||||
// s: session
|
||||
// id: the operation id to cancel
|
||||
// return: nothing
|
||||
void jdns_cancel_query(jdns_session_t *s, int id);
|
||||
|
||||
// jdns_publish:
|
||||
// s: session
|
||||
// mode: JDNS_PUBLISH shared or unique
|
||||
// rec: the record data
|
||||
// return: id of this operation
|
||||
// note: supported record types: A, AAAA, SRV, CNAME, PTR, TXT, and HINFO.
|
||||
// if the published type is not one of these, raw rdata must be set.
|
||||
int jdns_publish(jdns_session_t *s, int mode, const jdns_rr_t *rec);
|
||||
|
||||
// jdns_update_publish:
|
||||
// s: session
|
||||
// id: the operation id to update
|
||||
// rec: the record data
|
||||
// return: nothing
|
||||
void jdns_update_publish(jdns_session_t *s, int id, const jdns_rr_t *rec);
|
||||
|
||||
// jdns_cancel_publish:
|
||||
// s: session
|
||||
// id: the operation id to cancel
|
||||
// return: nothing
|
||||
void jdns_cancel_publish(jdns_session_t *s, int id);
|
||||
|
||||
// jdns_step:
|
||||
// s: session
|
||||
// return: JDNS_STEP flags OR'd together
|
||||
int jdns_step(jdns_session_t *s);
|
||||
|
||||
// jdns_next_timer:
|
||||
// s: session
|
||||
// return: milliseconds until timeout
|
||||
int jdns_next_timer(jdns_session_t *s);
|
||||
|
||||
// jdns_set_handle_readable:
|
||||
// s: session
|
||||
// handle: handle that is now readable
|
||||
// return: nothing
|
||||
void jdns_set_handle_readable(jdns_session_t *s, int handle);
|
||||
|
||||
// jdns_set_handle_writable:
|
||||
// s: session
|
||||
// handle: handle that is now writable
|
||||
// return: nothing
|
||||
void jdns_set_handle_writable(jdns_session_t *s, int handle);
|
||||
|
||||
// jdns_next_event:
|
||||
// s: session
|
||||
// return: newly allocated event, or zero if none are ready
|
||||
jdns_event_t *jdns_next_event(jdns_session_t *s);
|
||||
|
||||
// jdns_system_dnsparams:
|
||||
// return: newly allocated dnsparams from the system
|
||||
jdns_dnsparams_t *jdns_system_dnsparams();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
27
iris-legacy/iris/irisnet/jdns/jdns.pri
Normal file
27
iris-legacy/iris/irisnet/jdns/jdns.pri
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# qmake project include file
|
||||
|
||||
QT *= network
|
||||
|
||||
windows:{
|
||||
LIBS += -lWs2_32 -lAdvapi32
|
||||
}
|
||||
unix:{
|
||||
#QMAKE_CFLAGS += -pedantic
|
||||
}
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/jdns_packet.h \
|
||||
$$PWD/jdns_mdnsd.h \
|
||||
$$PWD/jdns_p.h \
|
||||
$$PWD/jdns.h \
|
||||
$$PWD/qjdns_sock.h \
|
||||
$$PWD/qjdns.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/jdns_util.c \
|
||||
$$PWD/jdns_packet.c \
|
||||
$$PWD/jdns_mdnsd.c \
|
||||
$$PWD/jdns_sys.c \
|
||||
$$PWD/jdns.c \
|
||||
$$PWD/qjdns_sock.cpp \
|
||||
$$PWD/qjdns.cpp
|
||||
9
iris-legacy/iris/irisnet/jdns/jdns.pro
Normal file
9
iris-legacy/iris/irisnet/jdns/jdns.pro
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
QT -= gui
|
||||
QT += network
|
||||
|
||||
include(jdns.pri)
|
||||
|
||||
SOURCES += \
|
||||
main.cpp
|
||||
1097
iris-legacy/iris/irisnet/jdns/jdns_mdnsd.c
Normal file
1097
iris-legacy/iris/irisnet/jdns/jdns_mdnsd.c
Normal file
File diff suppressed because it is too large
Load diff
120
iris-legacy/iris/irisnet/jdns/jdns_mdnsd.h
Normal file
120
iris-legacy/iris/irisnet/jdns/jdns_mdnsd.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (C) 2005 Jeremie Miller
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef JDNS_MDNSD_H
|
||||
#define JDNS_MDNSD_H
|
||||
|
||||
#include "jdns_p.h"
|
||||
|
||||
struct mytimeval
|
||||
{
|
||||
unsigned long int tv_sec; /* seconds */
|
||||
unsigned long int tv_usec; /* microseconds */
|
||||
};
|
||||
|
||||
typedef struct mdnsd_struct *mdnsd; // main daemon data
|
||||
typedef struct mdnsdr_struct *mdnsdr; // record entry
|
||||
// answer data
|
||||
typedef struct mdnsda_struct
|
||||
{
|
||||
unsigned char *name;
|
||||
unsigned short int type;
|
||||
unsigned long int ttl;
|
||||
unsigned long int real_ttl;
|
||||
unsigned short int rdlen;
|
||||
unsigned char *rdata;
|
||||
unsigned long int ip; // A
|
||||
unsigned char *rdname; // NS/CNAME/PTR/SRV
|
||||
struct { unsigned short int priority, weight, port; } srv; // SRV
|
||||
} *mdnsda;
|
||||
|
||||
///////////
|
||||
// Global functions
|
||||
//
|
||||
// create a new mdns daemon for the given class of names (usually 1) and maximum frame size
|
||||
mdnsd mdnsd_new(int class, int frame, int port, int (*time_now)(mdnsd d, void *arg), int (*rand_int)(mdnsd d, void *arg), void *arg);
|
||||
//
|
||||
// gracefully shutdown the daemon, use mdnsd_out() to get the last packets
|
||||
void mdnsd_shutdown(mdnsd d);
|
||||
//
|
||||
// flush all cached records (network/interface changed)
|
||||
void mdnsd_flush(mdnsd d);
|
||||
//
|
||||
// free given mdnsd (should have used mdnsd_shutdown() first!)
|
||||
void mdnsd_free(mdnsd d);
|
||||
//
|
||||
///////////
|
||||
|
||||
///////////
|
||||
// I/O functions
|
||||
//
|
||||
// incoming message from host (to be cached/processed)
|
||||
void mdnsd_in(mdnsd d, const jdns_packet_t *m, const jdns_response_t *resp, const jdns_address_t *addr, unsigned short int port);
|
||||
//
|
||||
// outgoing messge to be delivered to host, returns >0 if one was returned and m/ip/port set
|
||||
int mdnsd_out(mdnsd d, jdns_packet_t **m, jdns_address_t **addr, unsigned short int *port);
|
||||
//
|
||||
// returns the max wait-time until mdnsd_out() needs to be called again
|
||||
struct mytimeval *mdnsd_sleep(mdnsd d);
|
||||
//
|
||||
////////////
|
||||
|
||||
///////////
|
||||
// Q/A functions
|
||||
//
|
||||
// register a new query
|
||||
// answer(record, arg) is called whenever one is found/changes/expires (immediate or anytime after, mdnsda valid until ->ttl==0)
|
||||
// either answer returns -1, or another mdnsd_query with a NULL answer will remove/unregister this query
|
||||
void mdnsd_query(mdnsd d, char *host, int type, int (*answer)(mdnsda a, void *arg), void *arg);
|
||||
//
|
||||
// returns the first (if last == NULL) or next answer after last from the cache
|
||||
// mdnsda only valid until an I/O function is called
|
||||
mdnsda mdnsd_list(mdnsd d, char *host, int type, mdnsda last);
|
||||
//
|
||||
///////////
|
||||
|
||||
///////////
|
||||
// Publishing functions
|
||||
//
|
||||
// create a new unique record (try mdnsda_list first to make sure it's not used)
|
||||
// conflict(arg) called at any point when one is detected and unable to recover
|
||||
// after the first data is set_*(), any future changes effectively expire the old one and attempt to create a new unique record
|
||||
mdnsdr mdnsd_unique(mdnsd d, char *host, int type, long int ttl, void (*pubresult)(int result, char *host, int type, void *arg), void *arg);
|
||||
//
|
||||
// create a new shared record
|
||||
mdnsdr mdnsd_shared(mdnsd d, char *host, int type, long int ttl);
|
||||
//
|
||||
// de-list the given record
|
||||
void mdnsd_done(mdnsd d, mdnsdr r);
|
||||
//
|
||||
// these all set/update the data for the given record, nothing is published until they are called
|
||||
void mdnsd_set_raw(mdnsd d, mdnsdr r, char *data, int len);
|
||||
void mdnsd_set_host(mdnsd d, mdnsdr r, char *name);
|
||||
void mdnsd_set_ip(mdnsd d, mdnsdr r, unsigned long int ip);
|
||||
void mdnsd_set_srv(mdnsd d, mdnsdr r, int priority, int weight, int port, char *name);
|
||||
//
|
||||
///////////
|
||||
|
||||
|
||||
#endif
|
||||
83
iris-legacy/iris/irisnet/jdns/jdns_p.h
Normal file
83
iris-legacy/iris/irisnet/jdns/jdns_p.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef JDNS_P_H
|
||||
#define JDNS_P_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||
# define JDNS_OS_WIN
|
||||
#else
|
||||
# define JDNS_OS_UNIX
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__))
|
||||
# define JDNS_OS_MAC
|
||||
#endif
|
||||
|
||||
#ifdef JDNS_OS_WIN
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef JDNS_OS_UNIX
|
||||
# include <unistd.h>
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "jdns.h"
|
||||
#include "jdns_packet.h"
|
||||
|
||||
// jdns_util.c
|
||||
void *jdns_alloc(int size);
|
||||
void *jdns_realloc(void *p, int size);
|
||||
void jdns_free(void *p);
|
||||
char *jdns_strdup(const char *s);
|
||||
unsigned char *jdns_copy_array(const unsigned char *src, int size);
|
||||
int jdns_domain_cmp(const unsigned char *a, const unsigned char *b);
|
||||
|
||||
int jdns_string_indexOf(const jdns_string_t *s, unsigned char c, int pos);
|
||||
jdns_stringlist_t *jdns_string_split(const jdns_string_t *s, unsigned char sep);
|
||||
|
||||
jdns_dnshost_t *jdns_dnshost_new();
|
||||
jdns_dnshost_t *jdns_dnshost_copy(const jdns_dnshost_t *a);
|
||||
void jdns_dnshost_delete(jdns_dnshost_t *a);
|
||||
jdns_dnshostlist_t *jdns_dnshostlist_new();
|
||||
jdns_dnshostlist_t *jdns_dnshostlist_copy(const jdns_dnshostlist_t *a);
|
||||
void jdns_dnshostlist_delete(jdns_dnshostlist_t *a);
|
||||
void jdns_dnshostlist_append(jdns_dnshostlist_t *a, const jdns_dnshost_t *host);
|
||||
|
||||
jdns_rr_t *jdns_rr_from_resource(const jdns_packet_resource_t *pr, const jdns_packet_t *ref);
|
||||
void jdns_response_remove_extra(jdns_response_t *r);
|
||||
void jdns_response_remove_answer(jdns_response_t *r, int pos);
|
||||
|
||||
#define alloc_type(type) (type *)jdns_alloc(sizeof(type))
|
||||
#define _ustrdup(str) (unsigned char *)jdns_strdup((const char *)str)
|
||||
#define _ustrlen(str) strlen((const char *)str)
|
||||
#define _ustrcmp(a, b) strcmp((const char *)a, (const char *)b)
|
||||
|
||||
#endif
|
||||
989
iris-legacy/iris/irisnet/jdns/jdns_packet.c
Normal file
989
iris-legacy/iris/irisnet/jdns/jdns_packet.c
Normal file
|
|
@ -0,0 +1,989 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "jdns_packet.h"
|
||||
|
||||
#include "jdns_p.h"
|
||||
|
||||
// jer's endian functions
|
||||
static unsigned short int net2short(const unsigned char **bufp)
|
||||
{
|
||||
unsigned short int i;
|
||||
i = **bufp;
|
||||
i <<= 8;
|
||||
i |= *(*bufp + 1);
|
||||
*bufp += 2;
|
||||
return i;
|
||||
}
|
||||
|
||||
static unsigned long int net2long(const unsigned char **bufp)
|
||||
{
|
||||
unsigned long int l;
|
||||
l = **bufp;
|
||||
l <<= 8;
|
||||
l |= *(*bufp + 1);
|
||||
l <<= 8;
|
||||
l |= *(*bufp + 2);
|
||||
l <<= 8;
|
||||
l |= *(*bufp + 3);
|
||||
*bufp += 4;
|
||||
return l;
|
||||
}
|
||||
|
||||
static void short2net(unsigned short int i, unsigned char **bufp)
|
||||
{
|
||||
*(*bufp + 1) = (unsigned char)i;
|
||||
i >>= 8;
|
||||
**bufp = (unsigned char)i;
|
||||
*bufp += 2;
|
||||
}
|
||||
|
||||
static void long2net(unsigned long int l, unsigned char **bufp)
|
||||
{
|
||||
*(*bufp + 3) = (unsigned char)l;
|
||||
l >>= 8;
|
||||
*(*bufp + 2) = (unsigned char)l;
|
||||
l >>= 8;
|
||||
*(*bufp + 1) = (unsigned char)l;
|
||||
l >>= 8;
|
||||
**bufp = (unsigned char)l;
|
||||
*bufp += 4;
|
||||
}
|
||||
|
||||
// label stuff
|
||||
typedef struct jdns_packet_label
|
||||
{
|
||||
JDNS_OBJECT
|
||||
int offset;
|
||||
jdns_string_t *value;
|
||||
} jdns_packet_label_t;
|
||||
|
||||
static void jdns_packet_label_delete(jdns_packet_label_t *a);
|
||||
static jdns_packet_label_t *jdns_packet_label_copy(const jdns_packet_label_t *a);
|
||||
|
||||
static jdns_packet_label_t *jdns_packet_label_new()
|
||||
{
|
||||
jdns_packet_label_t *a = JDNS_OBJECT_NEW(jdns_packet_label);
|
||||
a->offset = 0;
|
||||
a->value = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
jdns_packet_label_t *jdns_packet_label_copy(const jdns_packet_label_t *a)
|
||||
{
|
||||
jdns_packet_label_t *c = jdns_packet_label_new();
|
||||
c->offset = a->offset;
|
||||
if(a->value)
|
||||
c->value = jdns_string_copy(a->value);
|
||||
return c;
|
||||
}
|
||||
|
||||
void jdns_packet_label_delete(jdns_packet_label_t *a)
|
||||
{
|
||||
if(!a)
|
||||
return;
|
||||
jdns_string_delete(a->value);
|
||||
jdns_object_free(a);
|
||||
}
|
||||
|
||||
// gets an offset for decompression. does range and hop count checking also
|
||||
static int getoffset(const unsigned char *str, int refsize, int *hopsleft)
|
||||
{
|
||||
unsigned short int x;
|
||||
if(*hopsleft <= 0)
|
||||
return -1;
|
||||
--(*hopsleft);
|
||||
x = str[0] & 0x3f;
|
||||
x <<= 8;
|
||||
x |= str[1];
|
||||
// stay in bounds
|
||||
if(x >= refsize)
|
||||
return -1;
|
||||
return x;
|
||||
}
|
||||
|
||||
static int readlabel(const unsigned char *in, int insize, const unsigned char *ref, int refsize, int *_at, jdns_string_t **name)
|
||||
{
|
||||
int at;
|
||||
unsigned char out[255];
|
||||
int out_size;
|
||||
const unsigned char *label, *last;
|
||||
int hopped_yet;
|
||||
int hopsleft;
|
||||
int label_size;
|
||||
|
||||
at = *_at;
|
||||
|
||||
// stay in range
|
||||
if(at < 0 || at >= insize)
|
||||
return 0;
|
||||
|
||||
out_size = 0;
|
||||
label = in + at;
|
||||
hopped_yet = 0;
|
||||
last = in + insize;
|
||||
while(1)
|
||||
{
|
||||
// need a byte
|
||||
if(label + 1 > last)
|
||||
goto error;
|
||||
|
||||
// we make this a while loop instead of an 'if', in case
|
||||
// there's a pointer to a pointer. as a precaution,
|
||||
// we will hop no more than 8 times
|
||||
hopsleft = 8;
|
||||
while(*label & 0xc0)
|
||||
{
|
||||
int offset;
|
||||
|
||||
// need the next byte, too
|
||||
if(label + 2 > last)
|
||||
goto error;
|
||||
|
||||
offset = getoffset(label, refsize, &hopsleft);
|
||||
if(offset == -1)
|
||||
goto error;
|
||||
|
||||
label = ref + offset;
|
||||
if(!hopped_yet)
|
||||
{
|
||||
at += 2;
|
||||
hopped_yet = 1;
|
||||
last = ref + refsize;
|
||||
}
|
||||
|
||||
// need a byte
|
||||
if(label + 1 > last)
|
||||
goto error;
|
||||
}
|
||||
|
||||
label_size = *label & 0x3f;
|
||||
|
||||
// null label? then we're done
|
||||
if(label_size == 0)
|
||||
{
|
||||
if(!hopped_yet)
|
||||
++at;
|
||||
break;
|
||||
}
|
||||
|
||||
// enough source bytes? (length byte + length)
|
||||
if(label + label_size + 1 > last)
|
||||
goto error;
|
||||
|
||||
// enough dest bytes? (length + dot)
|
||||
if(out_size + label_size + 1 > 255)
|
||||
goto error;
|
||||
|
||||
memcpy(out + out_size, label + 1, label_size);
|
||||
out_size += label_size;
|
||||
out[out_size] = '.';
|
||||
++out_size;
|
||||
|
||||
if(!hopped_yet)
|
||||
at += label_size + 1;
|
||||
|
||||
label += label_size + 1;
|
||||
}
|
||||
|
||||
*_at = at;
|
||||
*name = jdns_string_new();
|
||||
jdns_string_set(*name, out, out_size);
|
||||
return 1;
|
||||
|
||||
error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
// this function compares labels in label format:
|
||||
// [length] [value ...] [length] [value ...] [0]
|
||||
static int matchlabel(const unsigned char *a, int asize, const unsigned char *b, int bsize, const unsigned char *ref, int refsize, int ahopsleft, int bhopsleft)
|
||||
{
|
||||
int n, alen, blen, offset;
|
||||
|
||||
// same pointer?
|
||||
if(a == b)
|
||||
return 1;
|
||||
|
||||
if(asize < 1 || bsize < 1)
|
||||
return 0;
|
||||
|
||||
// always ensure we get called without a pointer
|
||||
if(*a & 0xc0)
|
||||
{
|
||||
if(asize < 2)
|
||||
return 0;
|
||||
offset = getoffset(a, refsize, &ahopsleft);
|
||||
if(offset == -1)
|
||||
return 0;
|
||||
return matchlabel(ref + offset, refsize - offset, b, bsize, ref, refsize, ahopsleft, bhopsleft);
|
||||
}
|
||||
if(*b & 0xc0)
|
||||
{
|
||||
if(bsize < 2)
|
||||
return 0;
|
||||
offset = getoffset(b, refsize, &bhopsleft);
|
||||
if(offset == -1)
|
||||
return 0;
|
||||
return matchlabel(a, asize, ref + offset, refsize - offset, ref, refsize, ahopsleft, bhopsleft);
|
||||
}
|
||||
|
||||
alen = *a & 0x3f;
|
||||
blen = *b & 0x3f;
|
||||
|
||||
// must be same length
|
||||
if(alen != blen)
|
||||
return 0;
|
||||
|
||||
// done?
|
||||
if(alen == 0)
|
||||
return 1;
|
||||
|
||||
// length byte + length + first byte of next label
|
||||
if(asize < alen + 2)
|
||||
return 0;
|
||||
if(bsize < blen + 2)
|
||||
return 0;
|
||||
|
||||
// compare the value
|
||||
for(n = 1; n < alen + 1; ++n)
|
||||
{
|
||||
if(a[n] != b[n])
|
||||
return 0;
|
||||
}
|
||||
|
||||
// try next labels
|
||||
n = alen + 1;
|
||||
return matchlabel(a + n, asize - n, b + n, bsize - n, ref, refsize, ahopsleft, bhopsleft);
|
||||
}
|
||||
|
||||
int jdns_packet_name_isvalid(const unsigned char *name, int size)
|
||||
{
|
||||
int n, at, len;
|
||||
|
||||
// at least one byte, no larger than 254 (one byte is gained when
|
||||
// converting to a label, which has a 255 byte max)
|
||||
if(size < 1 || size > 254)
|
||||
return 0;
|
||||
|
||||
// last byte must be a dot
|
||||
if(name[size - 1] != '.')
|
||||
return 0;
|
||||
|
||||
// first byte can't be a dot if there are characters after
|
||||
if(size > 1 && name[0] == '.')
|
||||
return 0;
|
||||
|
||||
// each sublabel must be between 1 and 63 in length
|
||||
at = 0;
|
||||
while(1)
|
||||
{
|
||||
// search for dot or end
|
||||
for(n = at; n < size; ++n)
|
||||
{
|
||||
if(name[n] == '.')
|
||||
break;
|
||||
}
|
||||
// length of last one is always zero
|
||||
if(n >= size)
|
||||
break;
|
||||
|
||||
len = n - at;
|
||||
if(len < 1 || len > 63)
|
||||
return 0;
|
||||
at = n + 1; // skip over the dot
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// this function assumes label is pointing to a 255 byte buffer
|
||||
static int name_to_label(const jdns_string_t *name, unsigned char *label)
|
||||
{
|
||||
int n, i, at, len;
|
||||
|
||||
if(!jdns_packet_name_isvalid(name->data, name->size))
|
||||
return -1;
|
||||
|
||||
if(name->size == 1)
|
||||
{
|
||||
label[0] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
at = 0;
|
||||
i = 0;
|
||||
while(1)
|
||||
{
|
||||
// search for dot or end
|
||||
for(n = at; n < name->size; ++n)
|
||||
{
|
||||
if(name->data[n] == '.')
|
||||
break;
|
||||
}
|
||||
len = n - at;
|
||||
if(i + (len + 1) > 255) // length byte + length
|
||||
return 0;
|
||||
|
||||
label[i++] = len;
|
||||
memcpy(label + i, name->data + at, len);
|
||||
i += len;
|
||||
|
||||
if(n >= name->size) // end?
|
||||
break;
|
||||
at = n + 1; // skip over the dot
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// lookup list is made of jdns_packet_labels
|
||||
static int writelabel(const jdns_string_t *name, int at, int left, unsigned char **bufp, jdns_list_t *lookup)
|
||||
{
|
||||
unsigned char label[255];
|
||||
int n, i, len;
|
||||
unsigned char *l;
|
||||
unsigned char *ref;
|
||||
int refsize;
|
||||
|
||||
len = name_to_label(name, label);
|
||||
if(len == -1)
|
||||
return 0;
|
||||
|
||||
ref = *bufp - at;
|
||||
refsize = at + left;
|
||||
for(n = 0; label[n]; n += label[n] + 1)
|
||||
{
|
||||
for(i = 0; i < lookup->count; ++i)
|
||||
{
|
||||
jdns_packet_label_t *pl = (jdns_packet_label_t *)lookup->item[i];
|
||||
|
||||
if(matchlabel(label + n, len - n, pl->value->data, pl->value->size, ref, refsize, 8, 8))
|
||||
{
|
||||
// set up a pointer right here, overwriting
|
||||
// the length byte and the first content
|
||||
// byte of this section within 'label'.
|
||||
// this is safe, because the length value
|
||||
// will always be greater than zero,
|
||||
// ensuring we have two bytes available to
|
||||
// use.
|
||||
l = label + n;
|
||||
short2net((unsigned short int)pl->offset, &l);
|
||||
label[n] |= 0xc0;
|
||||
len = n + 2; // cut things short
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(label[n] & 0xc0) // double loop, so break again
|
||||
break;
|
||||
}
|
||||
|
||||
if(left < len)
|
||||
return 0;
|
||||
|
||||
// copy into buffer, point there now
|
||||
memcpy(*bufp, label, len);
|
||||
l = *bufp;
|
||||
*bufp += len;
|
||||
|
||||
// for each new label, store its location for future compression
|
||||
for(n = 0; l[n]; n += l[n] + 1)
|
||||
{
|
||||
jdns_string_t *str;
|
||||
jdns_packet_label_t *pl;
|
||||
if(l[n] & 0xc0)
|
||||
break;
|
||||
|
||||
pl = jdns_packet_label_new();
|
||||
str = jdns_string_new();
|
||||
jdns_string_set(str, l + n, len - n);
|
||||
pl->offset = l + n - ref;
|
||||
pl->value = str;
|
||||
jdns_list_insert(lookup, pl, -1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// jdns_packet_write
|
||||
//----------------------------------------------------------------------------
|
||||
#define JDNS_PACKET_WRITE_RAW 0
|
||||
#define JDNS_PACKET_WRITE_NAME 1
|
||||
|
||||
struct jdns_packet_write
|
||||
{
|
||||
JDNS_OBJECT
|
||||
int type;
|
||||
jdns_string_t *value;
|
||||
};
|
||||
|
||||
void jdns_packet_write_delete(jdns_packet_write_t *a);
|
||||
jdns_packet_write_t *jdns_packet_write_copy(const jdns_packet_write_t *a);
|
||||
|
||||
jdns_packet_write_t *jdns_packet_write_new()
|
||||
{
|
||||
jdns_packet_write_t *a = JDNS_OBJECT_NEW(jdns_packet_write);
|
||||
a->type = 0;
|
||||
a->value = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
jdns_packet_write_t *jdns_packet_write_copy(const jdns_packet_write_t *a)
|
||||
{
|
||||
jdns_packet_write_t *c = jdns_packet_write_new();
|
||||
c->type = a->type;
|
||||
if(a->value)
|
||||
c->value = jdns_string_copy(a->value);
|
||||
return c;
|
||||
}
|
||||
|
||||
void jdns_packet_write_delete(jdns_packet_write_t *a)
|
||||
{
|
||||
if(!a)
|
||||
return;
|
||||
jdns_string_delete(a->value);
|
||||
jdns_object_free(a);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// jdns_packet_question
|
||||
//----------------------------------------------------------------------------
|
||||
jdns_packet_question_t *jdns_packet_question_new()
|
||||
{
|
||||
jdns_packet_question_t *a = JDNS_OBJECT_NEW(jdns_packet_question);
|
||||
a->qname = 0;
|
||||
a->qtype = 0;
|
||||
a->qclass = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
jdns_packet_question_t *jdns_packet_question_copy(const jdns_packet_question_t *a)
|
||||
{
|
||||
jdns_packet_question_t *c = jdns_packet_question_new();
|
||||
if(a->qname)
|
||||
c->qname = jdns_string_copy(a->qname);
|
||||
c->qtype = a->qtype;
|
||||
c->qclass = a->qclass;
|
||||
return c;
|
||||
}
|
||||
|
||||
void jdns_packet_question_delete(jdns_packet_question_t *a)
|
||||
{
|
||||
if(!a)
|
||||
return;
|
||||
jdns_string_delete(a->qname);
|
||||
jdns_object_free(a);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// jdns_packet_resource
|
||||
//----------------------------------------------------------------------------
|
||||
jdns_packet_resource_t *jdns_packet_resource_new()
|
||||
{
|
||||
jdns_packet_resource_t *a = JDNS_OBJECT_NEW(jdns_packet_resource);
|
||||
a->qname = 0;
|
||||
a->qtype = 0;
|
||||
a->qclass = 0;
|
||||
a->ttl = 0;
|
||||
a->rdlength = 0;
|
||||
a->rdata = 0;
|
||||
|
||||
a->writelog = jdns_list_new();
|
||||
a->writelog->valueList = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
jdns_packet_resource_t *jdns_packet_resource_copy(const jdns_packet_resource_t *a)
|
||||
{
|
||||
jdns_packet_resource_t *c = jdns_packet_resource_new();
|
||||
if(a->qname)
|
||||
c->qname = jdns_string_copy(a->qname);
|
||||
c->qtype = a->qtype;
|
||||
c->qclass = a->qclass;
|
||||
c->ttl = a->ttl;
|
||||
c->rdlength = a->rdlength;
|
||||
c->rdata = jdns_copy_array(a->rdata, a->rdlength);
|
||||
|
||||
jdns_list_delete(c->writelog);
|
||||
c->writelog = jdns_list_copy(a->writelog);
|
||||
return c;
|
||||
}
|
||||
|
||||
void jdns_packet_resource_delete(jdns_packet_resource_t *a)
|
||||
{
|
||||
if(!a)
|
||||
return;
|
||||
jdns_string_delete(a->qname);
|
||||
if(a->rdata)
|
||||
jdns_free(a->rdata);
|
||||
jdns_list_delete(a->writelog);
|
||||
jdns_object_free(a);
|
||||
}
|
||||
|
||||
void jdns_packet_resource_add_bytes(jdns_packet_resource_t *a, const unsigned char *data, int size)
|
||||
{
|
||||
jdns_packet_write_t *write = jdns_packet_write_new();
|
||||
write->type = JDNS_PACKET_WRITE_RAW;
|
||||
write->value = jdns_string_new();
|
||||
jdns_string_set(write->value, data, size);
|
||||
jdns_list_insert_value(a->writelog, write, -1);
|
||||
jdns_packet_write_delete(write);
|
||||
}
|
||||
|
||||
void jdns_packet_resource_add_name(jdns_packet_resource_t *a, const jdns_string_t *name)
|
||||
{
|
||||
jdns_packet_write_t *write = jdns_packet_write_new();
|
||||
write->type = JDNS_PACKET_WRITE_NAME;
|
||||
write->value = jdns_string_copy(name);
|
||||
jdns_list_insert_value(a->writelog, write, -1);
|
||||
jdns_packet_write_delete(write);
|
||||
}
|
||||
|
||||
int jdns_packet_resource_read_name(const jdns_packet_resource_t *a, const jdns_packet_t *p, int *at, jdns_string_t **name)
|
||||
{
|
||||
return readlabel(a->rdata, a->rdlength, p->raw_data, p->raw_size, at, name);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// jdns_packet
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// note: both process_qsection and process_rrsection modify the 'dest' list,
|
||||
// even if later items cause an error. this turns out to be convenient
|
||||
// for handling truncated dns packets
|
||||
|
||||
static int process_qsection(jdns_list_t *dest, int count, const unsigned char *data, int size, const unsigned char **bufp)
|
||||
{
|
||||
int n;
|
||||
int offset, at;
|
||||
jdns_string_t *name = 0;
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = *bufp;
|
||||
for(n = 0; n < count; ++n)
|
||||
{
|
||||
jdns_packet_question_t *q;
|
||||
|
||||
offset = buf - data;
|
||||
at = 0;
|
||||
|
||||
if(!readlabel(data + offset, size - offset, data, size, &at, &name))
|
||||
goto error;
|
||||
|
||||
offset += at;
|
||||
|
||||
// need 4 more bytes
|
||||
if(size - offset < 4)
|
||||
goto error;
|
||||
|
||||
buf = data + offset;
|
||||
|
||||
q = jdns_packet_question_new();
|
||||
q->qname = name;
|
||||
name = 0;
|
||||
q->qtype = net2short(&buf);
|
||||
q->qclass = net2short(&buf);
|
||||
|
||||
jdns_list_insert_value(dest, q, -1);
|
||||
jdns_packet_question_delete(q);
|
||||
}
|
||||
|
||||
*bufp = buf;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
jdns_string_delete(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_rrsection(jdns_list_t *dest, int count, const unsigned char *data, int size, const unsigned char **bufp)
|
||||
{
|
||||
int n;
|
||||
int offset, at;
|
||||
jdns_string_t *name = 0;
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = *bufp;
|
||||
for(n = 0; n < count; ++n)
|
||||
{
|
||||
jdns_packet_resource_t *r;
|
||||
|
||||
offset = buf - data;
|
||||
at = 0;
|
||||
|
||||
if(!readlabel(data + offset, size - offset, data, size, &at, &name))
|
||||
goto error;
|
||||
|
||||
offset += at;
|
||||
|
||||
// need 10 more bytes
|
||||
if(offset + 10 > size)
|
||||
goto error;
|
||||
|
||||
buf = data + offset;
|
||||
|
||||
r = jdns_packet_resource_new();
|
||||
r->qname = name;
|
||||
name = 0;
|
||||
r->qtype = net2short(&buf);
|
||||
r->qclass = net2short(&buf);
|
||||
r->ttl = net2long(&buf);
|
||||
r->rdlength = net2short(&buf);
|
||||
|
||||
offset = buf - data;
|
||||
|
||||
// make sure we have enough for the rdata
|
||||
if(size - offset < r->rdlength)
|
||||
{
|
||||
jdns_packet_resource_delete(r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r->rdata = jdns_copy_array(buf, r->rdlength);
|
||||
buf += r->rdlength;
|
||||
|
||||
jdns_list_insert_value(dest, r, -1);
|
||||
jdns_packet_resource_delete(r);
|
||||
}
|
||||
|
||||
*bufp = buf;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
jdns_string_delete(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_qsection(const jdns_list_t *src, int at, int left, unsigned char **bufp, jdns_list_t *lookup)
|
||||
{
|
||||
unsigned char *buf, *start, *last;
|
||||
int n;
|
||||
|
||||
buf = *bufp;
|
||||
start = buf - at;
|
||||
last = buf + left;
|
||||
for(n = 0; n < src->count; ++n)
|
||||
{
|
||||
jdns_packet_question_t *q = (jdns_packet_question_t *)src->item[n];
|
||||
|
||||
if(!writelabel(q->qname, buf - start, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
|
||||
if(buf + 4 > last)
|
||||
goto error;
|
||||
|
||||
short2net(q->qtype, &buf);
|
||||
short2net(q->qclass, &buf);
|
||||
}
|
||||
|
||||
*bufp = buf;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_rrsection(const jdns_list_t *src, int at, int left, unsigned char **bufp, jdns_list_t *lookup)
|
||||
{
|
||||
unsigned char *buf, *start, *last, *rdlengthp;
|
||||
int n, i, rdlength;
|
||||
|
||||
buf = *bufp;
|
||||
start = buf - at;
|
||||
last = buf + left;
|
||||
for(n = 0; n < src->count; ++n)
|
||||
{
|
||||
jdns_packet_resource_t *r = (jdns_packet_resource_t *)src->item[n];
|
||||
|
||||
if(!writelabel(r->qname, buf - start, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
|
||||
if(buf + 10 > last)
|
||||
goto error;
|
||||
|
||||
short2net(r->qtype, &buf);
|
||||
short2net(r->qclass, &buf);
|
||||
long2net(r->ttl, &buf);
|
||||
|
||||
// skip over rdlength
|
||||
rdlengthp = buf;
|
||||
buf += 2;
|
||||
|
||||
// play write log
|
||||
rdlength = 0;
|
||||
for(i = 0; i < r->writelog->count; ++i)
|
||||
{
|
||||
jdns_packet_write_t *write = (jdns_packet_write_t *)r->writelog->item[i];
|
||||
if(write->type == JDNS_PACKET_WRITE_RAW)
|
||||
{
|
||||
if(buf + write->value->size > last)
|
||||
goto error;
|
||||
|
||||
memcpy(buf, write->value->data, write->value->size);
|
||||
buf += write->value->size;
|
||||
}
|
||||
else // JDNS_PACKET_WRITE_NAME
|
||||
{
|
||||
if(!writelabel(write->value, buf - start, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
i = buf - rdlengthp; // should be rdata size + 2
|
||||
short2net((unsigned short int)(i - 2), &rdlengthp);
|
||||
}
|
||||
|
||||
*bufp = buf;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
jdns_packet_t *jdns_packet_new()
|
||||
{
|
||||
jdns_packet_t *a = JDNS_OBJECT_NEW(jdns_packet);
|
||||
a->id = 0;
|
||||
a->opts.qr = 0;
|
||||
a->opts.opcode = 0;
|
||||
a->opts.aa = 0;
|
||||
a->opts.tc = 0;
|
||||
a->opts.rd = 0;
|
||||
a->opts.ra = 0;
|
||||
a->opts.z = 0;
|
||||
a->opts.rcode = 0;
|
||||
|
||||
a->questions = jdns_list_new();
|
||||
a->answerRecords = jdns_list_new();
|
||||
a->authorityRecords = jdns_list_new();
|
||||
a->additionalRecords = jdns_list_new();
|
||||
|
||||
a->questions->valueList = 1;
|
||||
a->answerRecords->valueList = 1;
|
||||
a->authorityRecords->valueList = 1;
|
||||
a->additionalRecords->valueList = 1;
|
||||
|
||||
a->fully_parsed = 0;
|
||||
|
||||
a->raw_size = 0;
|
||||
a->raw_data = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
jdns_packet_t *jdns_packet_copy(const jdns_packet_t *a)
|
||||
{
|
||||
jdns_packet_t *c = jdns_packet_new();
|
||||
c->id = a->id;
|
||||
c->opts.qr = a->opts.qr;
|
||||
c->opts.opcode = a->opts.opcode;
|
||||
c->opts.aa = a->opts.aa;
|
||||
c->opts.tc = a->opts.tc;
|
||||
c->opts.rd = a->opts.rd;
|
||||
c->opts.ra = a->opts.ra;
|
||||
c->opts.z = a->opts.z;
|
||||
c->opts.rcode = a->opts.rcode;
|
||||
|
||||
jdns_list_delete(c->questions);
|
||||
jdns_list_delete(c->answerRecords);
|
||||
jdns_list_delete(c->authorityRecords);
|
||||
jdns_list_delete(c->additionalRecords);
|
||||
c->questions = jdns_list_copy(a->questions);
|
||||
c->answerRecords = jdns_list_copy(a->answerRecords);
|
||||
c->authorityRecords = jdns_list_copy(a->authorityRecords);
|
||||
c->additionalRecords = jdns_list_copy(a->additionalRecords);
|
||||
|
||||
c->fully_parsed = a->fully_parsed;
|
||||
|
||||
c->raw_size = a->raw_size;
|
||||
c->raw_data = jdns_copy_array(a->raw_data, a->raw_size);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void jdns_packet_delete(jdns_packet_t *a)
|
||||
{
|
||||
if(!a)
|
||||
return;
|
||||
jdns_list_delete(a->questions);
|
||||
jdns_list_delete(a->answerRecords);
|
||||
jdns_list_delete(a->authorityRecords);
|
||||
jdns_list_delete(a->additionalRecords);
|
||||
if(a->raw_data)
|
||||
jdns_free(a->raw_data);
|
||||
jdns_object_free(a);
|
||||
}
|
||||
|
||||
int jdns_packet_import(jdns_packet_t **a, const unsigned char *data, int size)
|
||||
{
|
||||
jdns_packet_t *tmp = 0;
|
||||
const unsigned char *buf;
|
||||
|
||||
// need at least some data
|
||||
if(!data || size == 0)
|
||||
return 0;
|
||||
|
||||
// header (id + options + item counts) is 12 bytes
|
||||
if(size < 12)
|
||||
goto error;
|
||||
|
||||
tmp = jdns_packet_new();
|
||||
buf = data;
|
||||
|
||||
// id
|
||||
tmp->id = net2short(&buf);
|
||||
|
||||
// options
|
||||
if(buf[0] & 0x80) // qr is bit 7
|
||||
tmp->opts.qr = 1;
|
||||
tmp->opts.opcode = (buf[0] & 0x78) >> 3; // opcode is bits 6,5,4,3
|
||||
if(buf[0] & 0x04) // aa is bit 2
|
||||
tmp->opts.aa = 1;
|
||||
if(buf[0] & 0x02) // tc is bit 1
|
||||
tmp->opts.tc = 1;
|
||||
if(buf[0] & 0x01) // rd is bit 0
|
||||
tmp->opts.rd = 1;
|
||||
if(buf[1] & 0x80) // ra is bit 7 (second byte)
|
||||
tmp->opts.ra = 1;
|
||||
tmp->opts.z = (buf[1] & 0x70) >> 4; // z is bits 6,5,4
|
||||
tmp->opts.rcode = buf[1] & 0x0f; // rcode is bits 3,2,1,0
|
||||
buf += 2;
|
||||
|
||||
// item counts
|
||||
tmp->qdcount = net2short(&buf);
|
||||
tmp->ancount = net2short(&buf);
|
||||
tmp->nscount = net2short(&buf);
|
||||
tmp->arcount = net2short(&buf);
|
||||
|
||||
// if these fail, we don't count them as errors, since the packet
|
||||
// might have been truncated
|
||||
if(!process_qsection(tmp->questions, tmp->qdcount, data, size, &buf))
|
||||
goto skip;
|
||||
if(!process_rrsection(tmp->answerRecords, tmp->ancount, data, size, &buf))
|
||||
goto skip;
|
||||
if(!process_rrsection(tmp->authorityRecords, tmp->nscount, data, size, &buf))
|
||||
goto skip;
|
||||
if(!process_rrsection(tmp->additionalRecords, tmp->arcount, data, size, &buf))
|
||||
goto skip;
|
||||
|
||||
tmp->fully_parsed = 1;
|
||||
|
||||
skip:
|
||||
// keep the raw data for reference during rdata parsing
|
||||
tmp->raw_size = size;
|
||||
tmp->raw_data = jdns_copy_array(data, size);
|
||||
|
||||
*a = tmp;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
jdns_packet_delete(tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int jdns_packet_export(jdns_packet_t *a, int maxsize)
|
||||
{
|
||||
unsigned char *block = 0;
|
||||
unsigned char *buf, *last;
|
||||
unsigned char c;
|
||||
int size;
|
||||
jdns_list_t *lookup = 0; // to hold jdns_packet_label_t
|
||||
|
||||
// clear out any existing raw data before we begin
|
||||
if(a->raw_data)
|
||||
{
|
||||
jdns_free(a->raw_data);
|
||||
a->raw_data = 0;
|
||||
a->raw_size = 0;
|
||||
}
|
||||
|
||||
// preallocate
|
||||
size = maxsize;
|
||||
block = (unsigned char *)jdns_alloc(size);
|
||||
memset(block, 0, size);
|
||||
|
||||
buf = block;
|
||||
last = block + size;
|
||||
|
||||
if(size < 12)
|
||||
goto error;
|
||||
|
||||
short2net(a->id, &buf);
|
||||
if(a->opts.qr)
|
||||
buf[0] |= 0x80;
|
||||
c = (unsigned char)a->opts.opcode;
|
||||
buf[0] |= c << 3;
|
||||
if(a->opts.aa)
|
||||
buf[0] |= 0x04;
|
||||
if(a->opts.tc)
|
||||
buf[0] |= 0x02;
|
||||
if(a->opts.rd)
|
||||
buf[0] |= 0x01;
|
||||
if(a->opts.ra)
|
||||
buf[1] |= 0x80;
|
||||
c = (unsigned char)a->opts.z;
|
||||
buf[1] |= c << 4;
|
||||
c = (unsigned char)a->opts.rcode;
|
||||
buf[1] |= c;
|
||||
buf += 2;
|
||||
short2net((unsigned short int)a->questions->count, &buf);
|
||||
short2net((unsigned short int)a->answerRecords->count, &buf);
|
||||
short2net((unsigned short int)a->authorityRecords->count, &buf);
|
||||
short2net((unsigned short int)a->additionalRecords->count, &buf);
|
||||
|
||||
// append sections
|
||||
lookup = jdns_list_new();
|
||||
lookup->autoDelete = 1;
|
||||
|
||||
if(!append_qsection(a->questions, buf - block, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
if(!append_rrsection(a->answerRecords, buf - block, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
if(!append_rrsection(a->authorityRecords, buf - block, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
if(!append_rrsection(a->additionalRecords, buf - block, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
|
||||
// done with all sections
|
||||
jdns_list_delete(lookup);
|
||||
|
||||
// condense
|
||||
size = buf - block;
|
||||
block = (unsigned char *)jdns_realloc(block, size);
|
||||
|
||||
// finalize
|
||||
a->qdcount = a->questions->count;
|
||||
a->ancount = a->answerRecords->count;
|
||||
a->nscount = a->authorityRecords->count;
|
||||
a->arcount = a->additionalRecords->count;
|
||||
a->raw_data = block;
|
||||
a->raw_size = size;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
jdns_list_delete(lookup);
|
||||
if(block)
|
||||
jdns_free(block);
|
||||
return 0;
|
||||
}
|
||||
116
iris-legacy/iris/irisnet/jdns/jdns_packet.h
Normal file
116
iris-legacy/iris/irisnet/jdns/jdns_packet.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef JDNS_PACKET_H
|
||||
#define JDNS_PACKET_H
|
||||
|
||||
#include "jdns.h"
|
||||
|
||||
// -- howto --
|
||||
//
|
||||
// writing packets:
|
||||
// 1) call jdns_packet_new()
|
||||
// 2) populate the jdns_packet_t structure, using the functions
|
||||
// as necessary
|
||||
// 3) call jdns_packet_export() to populate the raw data of the packet
|
||||
//
|
||||
// reading packets:
|
||||
// 1) call jdns_packet_new()
|
||||
// 2) call jdns_packet_import() with the raw data
|
||||
// 3) the jdns_packet_t structure is now populated
|
||||
//
|
||||
// IMPORTANT: all names must be valid. that is, ending in a dot character
|
||||
|
||||
int jdns_packet_name_isvalid(const unsigned char *name, int size); // 0 if not valid
|
||||
|
||||
typedef struct jdns_packet_question
|
||||
{
|
||||
JDNS_OBJECT
|
||||
jdns_string_t *qname;
|
||||
unsigned short int qtype, qclass;
|
||||
} jdns_packet_question_t;
|
||||
|
||||
jdns_packet_question_t *jdns_packet_question_new();
|
||||
jdns_packet_question_t *jdns_packet_question_copy(const jdns_packet_question_t *a);
|
||||
void jdns_packet_question_delete(jdns_packet_question_t *a);
|
||||
|
||||
typedef struct jdns_packet_write jdns_packet_write_t;
|
||||
typedef struct jdns_packet jdns_packet_t;
|
||||
|
||||
typedef struct jdns_packet_resource
|
||||
{
|
||||
JDNS_OBJECT
|
||||
jdns_string_t *qname;
|
||||
unsigned short int qtype, qclass;
|
||||
unsigned long int ttl;
|
||||
unsigned short int rdlength;
|
||||
unsigned char *rdata;
|
||||
|
||||
// private
|
||||
jdns_list_t *writelog; // jdns_packet_write_t
|
||||
} jdns_packet_resource_t;
|
||||
|
||||
jdns_packet_resource_t *jdns_packet_resource_new();
|
||||
jdns_packet_resource_t *jdns_packet_resource_copy(const jdns_packet_resource_t *a);
|
||||
void jdns_packet_resource_delete(jdns_packet_resource_t *a);
|
||||
void jdns_packet_resource_add_bytes(jdns_packet_resource_t *a, const unsigned char *data, int size);
|
||||
void jdns_packet_resource_add_name(jdns_packet_resource_t *a, const jdns_string_t *name);
|
||||
int jdns_packet_resource_read_name(const jdns_packet_resource_t *a, const jdns_packet_t *p, int *at, jdns_string_t **name);
|
||||
|
||||
struct jdns_packet
|
||||
{
|
||||
JDNS_OBJECT
|
||||
unsigned short int id;
|
||||
struct
|
||||
{
|
||||
unsigned short qr, opcode, aa, tc, rd, ra, z, rcode;
|
||||
} opts;
|
||||
|
||||
// item counts as specified by the packet. do not use these
|
||||
// for iteration over the item lists, since they can be wrong
|
||||
// if the packet is truncated.
|
||||
int qdcount, ancount, nscount, arcount;
|
||||
|
||||
// value lists
|
||||
jdns_list_t *questions; // jdns_packet_question_t
|
||||
jdns_list_t *answerRecords; // jdns_packet_resource_t
|
||||
jdns_list_t *authorityRecords; // jdns_packet_resource_t
|
||||
jdns_list_t *additionalRecords; // jdns_packet_resource_t
|
||||
|
||||
// since dns packets are allowed to be truncated, it is possible
|
||||
// for a packet to not get fully parsed yet still be considered
|
||||
// successfully parsed. this flag means the packet was fully
|
||||
// parsed also.
|
||||
int fully_parsed;
|
||||
|
||||
int raw_size;
|
||||
unsigned char *raw_data;
|
||||
};
|
||||
|
||||
jdns_packet_t *jdns_packet_new();
|
||||
jdns_packet_t *jdns_packet_copy(const jdns_packet_t *a);
|
||||
void jdns_packet_delete(jdns_packet_t *a);
|
||||
int jdns_packet_import(jdns_packet_t **a, const unsigned char *data, int size); // 0 on fail
|
||||
int jdns_packet_export(jdns_packet_t *a, int maxsize); // 0 on fail
|
||||
|
||||
#endif
|
||||
822
iris-legacy/iris/irisnet/jdns/jdns_sys.c
Normal file
822
iris-legacy/iris/irisnet/jdns/jdns_sys.c
Normal file
|
|
@ -0,0 +1,822 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
this code probes the system for dns settings. blah.
|
||||
|
||||
q3dns strategies
|
||||
----------------
|
||||
|
||||
windows:
|
||||
|
||||
domain name, name server, "search list" found in windows registry here:
|
||||
|
||||
HKEY_LOCAL_MACHINE
|
||||
System\CurrentControlSet\Services\Tcpip\Parameters <-- win nt+
|
||||
System\CurrentControlSet\Services\VxD\MSTCP <-- win 98
|
||||
|
||||
for domain, try DhcpDomain else Domain
|
||||
for name servers, try DhcpNameServer, else NameServer
|
||||
for search list, try SearchList
|
||||
|
||||
iphlpapi.dll : GetNetworkParams(PFIXED_INFO, PULONG);
|
||||
|
||||
info->DomainName
|
||||
info->DnsServerList (if not null, use it, and loop through ->Next until
|
||||
null)
|
||||
no search list
|
||||
|
||||
first try getnetworkparams. if that fails, try the nt regkey then the 98
|
||||
regkey. it seems that search list can only come from the registry, so
|
||||
maybe we need to grab that entry even if getnetworkparams works.
|
||||
|
||||
in the case of the registry, the nameserver and searchlist entries are
|
||||
delimited by spaces on win nt and commas on win 98. probably a good
|
||||
idea to simplify white space first (chop away space at start and end,
|
||||
reduce all sections of spaces to one char). also, lowercase the search
|
||||
list.
|
||||
|
||||
qt doesn't read the hosts file on windows. this might be a good idea, but
|
||||
probably not worth it.
|
||||
|
||||
unix:
|
||||
|
||||
read /etc/resolv.conf manually:
|
||||
for each line, split at spaces
|
||||
if the first item is "nameserver", then there should be an IP address
|
||||
following it. note: may contain mixed ipv4 and ipv6 addresses
|
||||
if the first item is "search", all other items are added to the domain
|
||||
list
|
||||
if the first item is "domain", then the next item should be added to the
|
||||
domain list.
|
||||
do case-insensitive matching for the item types
|
||||
for search/domain, the items are in the 8-bit system locale
|
||||
|
||||
info can also be fetched using system calls. we use the res_* stuff here.
|
||||
first we should detect for a "modern res api". this is available from
|
||||
glibc 2.3 and onward. use the following scheme to check for it:
|
||||
|
||||
#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2)
|
||||
&& (__GLIBC_MINOR__ >= 3)))
|
||||
// modern res api
|
||||
#endif
|
||||
|
||||
on mac we should look up res_init in the system library. see:
|
||||
qt_mac_resolve_sys(RTLD_NEXT, "res_init"); for a hint.
|
||||
otherwise we can just use res_init() straight.
|
||||
|
||||
under a modern res api, we do:
|
||||
struct __res_state res;
|
||||
res_ninit(&res);
|
||||
otherwise, we simply call res_init(). for the modern api, we use the "res"
|
||||
struct that we made. otherwise, we use the global "_res" struct.
|
||||
|
||||
read the res struct to obtain the name servers, search list, and domain.
|
||||
lowercase the search list and domain.
|
||||
|
||||
qt tries the file, and if that fails it tries the syscalls. we may want to
|
||||
do the syscalls first, or even just do both all the time.
|
||||
|
||||
read /etc/hosts manually:
|
||||
for each line
|
||||
if there is a '#' character in the line, remove it and everything to
|
||||
the right
|
||||
simplify white space
|
||||
convert to lowercase
|
||||
split the line at spaces
|
||||
first item is the ip address
|
||||
all remaining items are hostnames
|
||||
|
||||
note: these hosts could also be used for reverse-dns too
|
||||
note2: Windows has a hosts file as well (like C:\WINDOWS\hosts)
|
||||
*/
|
||||
|
||||
#include "jdns_p.h"
|
||||
|
||||
#ifdef JDNS_OS_WIN
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef JDNS_OS_UNIX
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/nameser.h>
|
||||
# include <resolv.h>
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#define string_indexOf jdns_string_indexOf
|
||||
#define string_split jdns_string_split
|
||||
|
||||
static int char_isspace(unsigned char c)
|
||||
{
|
||||
if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *string_getnextword(unsigned char *in, int size, int pos, int *newpos)
|
||||
{
|
||||
int n;
|
||||
int at;
|
||||
int len;
|
||||
unsigned char *out;
|
||||
|
||||
at = pos;
|
||||
|
||||
// skip any space at the start
|
||||
while(at < size && char_isspace(in[at]))
|
||||
++at;
|
||||
|
||||
// all space? no word then
|
||||
if(at >= size)
|
||||
return 0;
|
||||
|
||||
// skip until a space or end
|
||||
n = at;
|
||||
while(n < size && !char_isspace(in[n]))
|
||||
++n;
|
||||
len = n - at;
|
||||
|
||||
// allocate length + zero byte
|
||||
out = (unsigned char *)jdns_alloc(len + 1);
|
||||
if(!out)
|
||||
return 0;
|
||||
memcpy(out, in + at, len);
|
||||
out[len] = 0;
|
||||
*newpos = at + len;
|
||||
return out;
|
||||
}
|
||||
|
||||
static jdns_string_t *string_simplify(const jdns_string_t *in)
|
||||
{
|
||||
int n;
|
||||
int pos;
|
||||
int total;
|
||||
unsigned char *out;
|
||||
int outlen;
|
||||
jdns_string_t *outstr;
|
||||
jdns_stringlist_t *wordlist;
|
||||
|
||||
// gather words and total of lengths
|
||||
pos = 0;
|
||||
total = 0;
|
||||
wordlist = jdns_stringlist_new();
|
||||
while(1)
|
||||
{
|
||||
jdns_string_t *word;
|
||||
unsigned char *str = string_getnextword(in->data, in->size, pos, &pos);
|
||||
if(!str)
|
||||
break;
|
||||
word = jdns_string_new();
|
||||
jdns_string_set_cstr(word, (char *)str);
|
||||
jdns_free(str);
|
||||
jdns_stringlist_append(wordlist, word);
|
||||
total += word->size;
|
||||
jdns_string_delete(word);
|
||||
}
|
||||
|
||||
if(total == 0)
|
||||
{
|
||||
jdns_stringlist_delete(wordlist);
|
||||
|
||||
outstr = jdns_string_new();
|
||||
jdns_string_set_cstr(outstr, "");
|
||||
return outstr;
|
||||
}
|
||||
|
||||
// we need to allocate space for total lengths and wordcount-1 spaces
|
||||
outlen = total + (wordlist->count - 1);
|
||||
out = (unsigned char *)jdns_alloc(outlen);
|
||||
|
||||
// lay out the words
|
||||
pos = 0;
|
||||
for(n = 0; n < wordlist->count; ++n)
|
||||
{
|
||||
unsigned char *data = wordlist->item[n]->data;
|
||||
int size = wordlist->item[n]->size;
|
||||
memcpy(out + pos, data, size);
|
||||
pos += size;
|
||||
|
||||
// if this is not the last word, append a space
|
||||
if(n + 1 < wordlist->count)
|
||||
out[pos++] = ' ';
|
||||
}
|
||||
jdns_stringlist_delete(wordlist);
|
||||
|
||||
outstr = jdns_string_new();
|
||||
jdns_string_set(outstr, out, outlen);
|
||||
jdns_free(out);
|
||||
return outstr;
|
||||
}
|
||||
|
||||
static jdns_string_t *string_tolower(const jdns_string_t *in)
|
||||
{
|
||||
int n;
|
||||
jdns_string_t *out = jdns_string_copy(in);
|
||||
for(n = 0; n < out->size; ++n)
|
||||
out->data[n] = tolower(out->data[n]);
|
||||
return out;
|
||||
}
|
||||
|
||||
static jdns_string_t *file_nextline(FILE *f)
|
||||
{
|
||||
int at, size;
|
||||
unsigned char *buf;
|
||||
jdns_string_t *str;
|
||||
|
||||
size = 1023;
|
||||
buf = (unsigned char *)jdns_alloc(size);
|
||||
at = 0;
|
||||
while(1)
|
||||
{
|
||||
unsigned char c = fgetc(f);
|
||||
if(feof(f))
|
||||
{
|
||||
jdns_free(buf);
|
||||
return 0;
|
||||
}
|
||||
if(c == '\n')
|
||||
break;
|
||||
if(c == '\r')
|
||||
continue;
|
||||
if(at < 1023)
|
||||
buf[at++] = c;
|
||||
}
|
||||
|
||||
str = jdns_string_new();
|
||||
jdns_string_set(str, buf, at);
|
||||
jdns_free(buf);
|
||||
return str;
|
||||
}
|
||||
|
||||
static jdns_dnshostlist_t *read_hosts_file(const char *path)
|
||||
{
|
||||
jdns_dnshostlist_t *out;
|
||||
FILE *f;
|
||||
jdns_string_t *line, *simp;
|
||||
jdns_stringlist_t *parts;
|
||||
jdns_address_t *addr;
|
||||
int n;
|
||||
|
||||
out = jdns_dnshostlist_new();
|
||||
|
||||
f = fopen(path, "r");
|
||||
if(!f)
|
||||
return out;
|
||||
while(1)
|
||||
{
|
||||
line = file_nextline(f);
|
||||
if(!line)
|
||||
break;
|
||||
|
||||
// truncate at comment
|
||||
n = string_indexOf(line, '#', 0);
|
||||
if(n != -1)
|
||||
{
|
||||
line->size = n;
|
||||
line->data[n] = 0;
|
||||
}
|
||||
|
||||
simp = string_simplify(line);
|
||||
jdns_string_delete(line);
|
||||
|
||||
parts = string_split(simp, ' ');
|
||||
jdns_string_delete(simp);
|
||||
|
||||
if(parts->count < 2)
|
||||
{
|
||||
jdns_stringlist_delete(parts);
|
||||
continue;
|
||||
}
|
||||
|
||||
addr = jdns_address_new();
|
||||
if(!jdns_address_set_cstr(addr, (const char *)parts->item[0]->data))
|
||||
{
|
||||
jdns_address_delete(addr);
|
||||
jdns_stringlist_delete(parts);
|
||||
continue;
|
||||
}
|
||||
|
||||
for(n = 1; n < parts->count; ++n)
|
||||
{
|
||||
jdns_dnshost_t *h = jdns_dnshost_new();
|
||||
h->name = jdns_string_copy(parts->item[n]);
|
||||
h->address = jdns_address_copy(addr);
|
||||
jdns_dnshostlist_append(out, h);
|
||||
jdns_dnshost_delete(h);
|
||||
}
|
||||
|
||||
jdns_address_delete(addr);
|
||||
jdns_stringlist_delete(parts);
|
||||
}
|
||||
fclose(f);
|
||||
return out;
|
||||
}
|
||||
|
||||
static void apply_hosts_file(jdns_dnsparams_t *a, const char *path)
|
||||
{
|
||||
int n;
|
||||
jdns_dnshostlist_t *list;
|
||||
|
||||
list = read_hosts_file(path);
|
||||
for(n = 0; n < list->count; ++n)
|
||||
jdns_dnshostlist_append(a->hosts, list->item[n]);
|
||||
jdns_dnshostlist_delete(list);
|
||||
}
|
||||
|
||||
static int dnsparams_have_domain(const jdns_dnsparams_t *a, const jdns_string_t *domain)
|
||||
{
|
||||
int n;
|
||||
for(n = 0; n < a->domains->count; ++n)
|
||||
{
|
||||
jdns_string_t *str = a->domains->item[n];
|
||||
if(strcmp((const char *)str->data, (const char *)domain->data) == 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef JDNS_OS_WIN
|
||||
|
||||
// from Microsoft IPTypes.h
|
||||
#ifndef IP_TYPES_INCLUDED
|
||||
#define MAX_HOSTNAME_LEN 128
|
||||
#define MAX_DOMAIN_NAME_LEN 128
|
||||
#define MAX_SCOPE_ID_LEN 256
|
||||
typedef struct {
|
||||
char String[4 * 4];
|
||||
} IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;
|
||||
typedef struct _IP_ADDR_STRING {
|
||||
struct _IP_ADDR_STRING* Next;
|
||||
IP_ADDRESS_STRING IpAddress;
|
||||
IP_MASK_STRING IpMask;
|
||||
DWORD Context;
|
||||
} IP_ADDR_STRING, *PIP_ADDR_STRING;
|
||||
typedef struct {
|
||||
char HostName[MAX_HOSTNAME_LEN + 4] ;
|
||||
char DomainName[MAX_DOMAIN_NAME_LEN + 4];
|
||||
PIP_ADDR_STRING CurrentDnsServer;
|
||||
IP_ADDR_STRING DnsServerList;
|
||||
UINT NodeType;
|
||||
char ScopeId[MAX_SCOPE_ID_LEN + 4];
|
||||
UINT EnableRouting;
|
||||
UINT EnableProxy;
|
||||
UINT EnableDns;
|
||||
} FIXED_INFO, *PFIXED_INFO;
|
||||
#endif
|
||||
|
||||
typedef DWORD (WINAPI *GetNetworkParamsFunc)(PFIXED_INFO, PULONG);
|
||||
|
||||
static jdns_string_t *reg_readString(HKEY hk, const char *subkey)
|
||||
{
|
||||
char *buf;
|
||||
DWORD bufsize;
|
||||
int ret;
|
||||
jdns_string_t *str = 0;
|
||||
|
||||
bufsize = 1024;
|
||||
buf = (char *)jdns_alloc((int)bufsize);
|
||||
if(!buf)
|
||||
return 0;
|
||||
ret = RegQueryValueExA(hk, subkey, 0, 0, (LPBYTE)buf, &bufsize);
|
||||
if(ret == ERROR_MORE_DATA)
|
||||
{
|
||||
buf = (char *)jdns_realloc(buf, bufsize);
|
||||
if(!buf)
|
||||
{
|
||||
jdns_free(buf);
|
||||
return 0;
|
||||
}
|
||||
ret = RegQueryValueExA(hk, subkey, 0, 0, (LPBYTE)buf, &bufsize);
|
||||
}
|
||||
if(ret == ERROR_SUCCESS)
|
||||
{
|
||||
str = jdns_string_new();
|
||||
jdns_string_set_cstr(str, (char *)buf);
|
||||
}
|
||||
jdns_free(buf);
|
||||
return str;
|
||||
}
|
||||
|
||||
static jdns_dnsparams_t *dnsparams_get_winreg()
|
||||
{
|
||||
int n;
|
||||
jdns_dnsparams_t *params;
|
||||
HKEY key;
|
||||
int ret;
|
||||
char sep;
|
||||
jdns_string_t *str_domain, *str_nameserver, *str_searchlist;
|
||||
jdns_stringlist_t *list_nameserver, *list_searchlist;
|
||||
|
||||
sep = ' ';
|
||||
ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
||||
"System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
|
||||
0, KEY_READ, &key);
|
||||
if(ret != ERROR_SUCCESS)
|
||||
{
|
||||
sep = ',';
|
||||
ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
||||
"System\\CurrentControlSet\\Services\\VxD\\MSTCP",
|
||||
0, KEY_READ, &key);
|
||||
if(ret != ERROR_SUCCESS)
|
||||
return 0;
|
||||
}
|
||||
|
||||
str_domain = reg_readString(key, "DhcpDomain");
|
||||
if(!str_domain)
|
||||
str_domain = reg_readString(key, "Domain");
|
||||
str_nameserver = reg_readString(key, "DhcpNameServer");
|
||||
if(!str_nameserver)
|
||||
str_nameserver = reg_readString(key, "NameServer");
|
||||
str_searchlist = reg_readString(key, "SearchList");
|
||||
|
||||
RegCloseKey(key);
|
||||
|
||||
list_nameserver = 0;
|
||||
if(str_nameserver)
|
||||
{
|
||||
list_nameserver = string_split(str_nameserver, sep);
|
||||
jdns_string_delete(str_nameserver);
|
||||
}
|
||||
list_searchlist = 0;
|
||||
if(str_searchlist)
|
||||
{
|
||||
// lowercase the string
|
||||
jdns_string_t *p = string_tolower(str_searchlist);
|
||||
jdns_string_delete(str_searchlist);
|
||||
str_searchlist = p;
|
||||
|
||||
list_searchlist = string_split(str_searchlist, sep);
|
||||
jdns_string_delete(str_searchlist);
|
||||
}
|
||||
|
||||
params = jdns_dnsparams_new();
|
||||
if(list_nameserver)
|
||||
{
|
||||
// qt seems to do a strange thing here by running each name
|
||||
// server address through the q3dns setLabel function, and
|
||||
// then pulls the result as a list of addresses. i have
|
||||
// no idea why they do this, or how one IP address would
|
||||
// turn into anything else, let alone several addresses.
|
||||
// so, uh, we're not going to do that.
|
||||
for(n = 0; n < list_nameserver->count; ++n)
|
||||
{
|
||||
jdns_address_t *addr = jdns_address_new();
|
||||
if(jdns_address_set_cstr(addr, (char *)list_nameserver->item[n]->data))
|
||||
jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
jdns_stringlist_delete(list_nameserver);
|
||||
}
|
||||
if(str_domain)
|
||||
{
|
||||
if(str_domain->size > 0)
|
||||
jdns_dnsparams_append_domain(params, str_domain);
|
||||
jdns_string_delete(str_domain);
|
||||
}
|
||||
if(list_searchlist)
|
||||
{
|
||||
for(n = 0; n < list_searchlist->count; ++n)
|
||||
{
|
||||
if(list_searchlist->item[n]->size > 0)
|
||||
jdns_dnsparams_append_domain(params, list_searchlist->item[n]);
|
||||
}
|
||||
jdns_stringlist_delete(list_searchlist);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
static jdns_dnsparams_t *dnsparams_get_winsys()
|
||||
{
|
||||
jdns_dnsparams_t *params;
|
||||
GetNetworkParamsFunc myGetNetworkParams;
|
||||
DWORD ret;
|
||||
HINSTANCE lib;
|
||||
jdns_address_t *addr;
|
||||
jdns_string_t *str;
|
||||
IP_ADDR_STRING *ipstr;
|
||||
|
||||
lib = LoadLibraryA("iphlpapi");
|
||||
if(!lib)
|
||||
return 0;
|
||||
|
||||
params = 0;
|
||||
myGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress(lib, "GetNetworkParams");
|
||||
if(myGetNetworkParams)
|
||||
{
|
||||
ULONG bufsize = 0;
|
||||
ret = myGetNetworkParams(0, &bufsize);
|
||||
if(ret == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
FIXED_INFO *info = (FIXED_INFO *)jdns_alloc((int)bufsize);
|
||||
ret = myGetNetworkParams(info, &bufsize);
|
||||
if(ret == ERROR_SUCCESS)
|
||||
{
|
||||
params = jdns_dnsparams_new();
|
||||
ipstr = &info->DnsServerList;
|
||||
while(ipstr)
|
||||
{
|
||||
addr = jdns_address_new();
|
||||
if(jdns_address_set_cstr(addr, (char *)ipstr->IpAddress.String))
|
||||
jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
|
||||
jdns_address_delete(addr);
|
||||
ipstr = ipstr->Next;
|
||||
}
|
||||
str = jdns_string_new();
|
||||
jdns_string_set_cstr(str, info->DomainName);
|
||||
if(str->size > 0)
|
||||
jdns_dnsparams_append_domain(params, str);
|
||||
jdns_string_delete(str);
|
||||
}
|
||||
jdns_free(info);
|
||||
}
|
||||
}
|
||||
FreeLibrary(lib);
|
||||
return params;
|
||||
}
|
||||
|
||||
static void apply_win_hosts_file(jdns_dnsparams_t *a)
|
||||
{
|
||||
char *p, *str;
|
||||
int len;
|
||||
|
||||
p = getenv("WINDIR");
|
||||
if(!p)
|
||||
return;
|
||||
len = strlen(p);
|
||||
str = (char *)jdns_alloc(len + 100); // should be enough
|
||||
memcpy(str, p, len);
|
||||
strcpy(str + len, "\\system32\\drivers\\etc\\hosts"); // winnt+
|
||||
apply_hosts_file(a, str);
|
||||
strcpy(str + len, "\\hosts"); // win9x
|
||||
apply_hosts_file(a, str);
|
||||
jdns_free(str);
|
||||
}
|
||||
|
||||
static jdns_dnsparams_t *dnsparams_get_win()
|
||||
{
|
||||
int n;
|
||||
jdns_dnsparams_t *sys_params, *reg_params;
|
||||
|
||||
reg_params = dnsparams_get_winreg();
|
||||
sys_params = dnsparams_get_winsys();
|
||||
|
||||
// no sys params? take the reg params then
|
||||
if(!sys_params)
|
||||
{
|
||||
apply_win_hosts_file(reg_params);
|
||||
return reg_params;
|
||||
}
|
||||
|
||||
// sys params don't have a search list, so merge the domains from
|
||||
// the registry if possible
|
||||
if(reg_params)
|
||||
{
|
||||
for(n = 0; n < reg_params->domains->count; ++n)
|
||||
{
|
||||
jdns_string_t *reg_str = reg_params->domains->item[n];
|
||||
|
||||
// don't add dups
|
||||
if(!dnsparams_have_domain(sys_params, reg_str))
|
||||
jdns_dnsparams_append_domain(sys_params, reg_str);
|
||||
}
|
||||
jdns_dnsparams_delete(reg_params);
|
||||
}
|
||||
apply_win_hosts_file(sys_params);
|
||||
return sys_params;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef JDNS_OS_UNIX
|
||||
|
||||
static jdns_dnsparams_t *dnsparams_get_unixfiles()
|
||||
{
|
||||
FILE *f;
|
||||
int n;
|
||||
jdns_dnsparams_t *params;
|
||||
jdns_string_t *line, *simp;
|
||||
jdns_stringlist_t *parts;
|
||||
|
||||
params = jdns_dnsparams_new();
|
||||
|
||||
f = fopen("/etc/resolv.conf", "r");
|
||||
if(!f)
|
||||
return params;
|
||||
while(1)
|
||||
{
|
||||
line = file_nextline(f);
|
||||
if(!line)
|
||||
break;
|
||||
|
||||
// truncate at comment
|
||||
n = string_indexOf(line, '#', 0);
|
||||
if(n != -1)
|
||||
{
|
||||
line->size = n;
|
||||
line->data[n] = 0;
|
||||
}
|
||||
|
||||
simp = string_simplify(line);
|
||||
jdns_string_delete(line);
|
||||
|
||||
parts = string_split(simp, ' ');
|
||||
jdns_string_delete(simp);
|
||||
|
||||
if(parts->count < 2)
|
||||
{
|
||||
jdns_stringlist_delete(parts);
|
||||
continue;
|
||||
}
|
||||
|
||||
simp = string_tolower(parts->item[0]);
|
||||
if(strcmp((char *)simp->data, "nameserver") == 0)
|
||||
{
|
||||
jdns_address_t *addr = jdns_address_new();
|
||||
jdns_address_set_cstr(addr, (const char *)parts->item[1]->data);
|
||||
jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
else if(strcmp((char *)simp->data, "search") == 0)
|
||||
{
|
||||
for(n = 1; n < parts->count; ++n)
|
||||
{
|
||||
jdns_dnsparams_append_domain(params, parts->item[n]);
|
||||
}
|
||||
}
|
||||
else if(strcmp((char *)simp->data, "domain") == 0)
|
||||
{
|
||||
jdns_dnsparams_append_domain(params, parts->item[1]);
|
||||
}
|
||||
jdns_string_delete(simp);
|
||||
|
||||
jdns_stringlist_delete(parts);
|
||||
}
|
||||
fclose(f);
|
||||
return params;
|
||||
}
|
||||
|
||||
#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 3)))
|
||||
# define JDNS_MODERN_RES_API
|
||||
#endif
|
||||
|
||||
#ifndef JDNS_MODERN_RES_API
|
||||
typedef int (*res_init_func)();
|
||||
static int my_res_init()
|
||||
{
|
||||
#ifdef JDNS_OS_MAC
|
||||
res_init_func mac_res_init;
|
||||
|
||||
// look up res_init in the system library (qt does this, not sure why)
|
||||
mac_res_init = (res_init_func)dlsym(RTLD_NEXT, "res_init");
|
||||
if(!mac_res_init)
|
||||
return -1;
|
||||
return mac_res_init();
|
||||
#else
|
||||
return res_init();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __res_state_ext
|
||||
# define USE_EXTEXT
|
||||
#endif
|
||||
|
||||
static jdns_dnsparams_t *dnsparams_get_unixsys()
|
||||
{
|
||||
int n;
|
||||
jdns_dnsparams_t *params;
|
||||
|
||||
#ifdef JDNS_MODERN_RES_API
|
||||
struct __res_state res;
|
||||
memset(&res, 0, sizeof(struct __res_state));
|
||||
n = res_ninit(&res);
|
||||
#define RESVAR res
|
||||
#else
|
||||
n = my_res_init();
|
||||
#define RESVAR _res
|
||||
#endif
|
||||
|
||||
params = jdns_dnsparams_new();
|
||||
|
||||
// error initializing?
|
||||
if(n == -1)
|
||||
return params;
|
||||
|
||||
// nameservers - ipv6
|
||||
for(n = 0; n < MAXNS && n < RESVAR._u._ext.nscount; ++n)
|
||||
{
|
||||
jdns_address_t *addr;
|
||||
struct sockaddr_in6 *sa6;
|
||||
|
||||
#ifdef USE_EXTEXT
|
||||
sa6 = ((struct sockaddr_in6 *)RESVAR._u._ext.ext) + n;
|
||||
#else
|
||||
sa6 = RESVAR._u._ext.nsaddrs[n];
|
||||
#endif
|
||||
|
||||
if(sa6 == NULL)
|
||||
continue;
|
||||
addr = jdns_address_new();
|
||||
jdns_address_set_ipv6(addr, sa6->sin6_addr.s6_addr);
|
||||
jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
|
||||
// nameservers - ipv4
|
||||
for(n = 0; n < MAXNS && n < RESVAR.nscount; ++n)
|
||||
{
|
||||
jdns_address_t *addr = jdns_address_new();
|
||||
jdns_address_set_ipv4(addr, ntohl(RESVAR.nsaddr_list[n].sin_addr.s_addr));
|
||||
jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
|
||||
// domain name
|
||||
if(strlen(RESVAR.defdname) > 0)
|
||||
{
|
||||
jdns_string_t *str;
|
||||
jdns_string_t *p;
|
||||
str = jdns_string_new();
|
||||
jdns_string_set_cstr(str, RESVAR.defdname);
|
||||
p = string_tolower(str);
|
||||
jdns_string_delete(str);
|
||||
str = p;
|
||||
jdns_dnsparams_append_domain(params, str);
|
||||
jdns_string_delete(str);
|
||||
}
|
||||
|
||||
// search list
|
||||
#ifdef MAXDFLSRCH
|
||||
for(n = 0; n < MAXDFLSRCH && RESVAR.dnsrch[n]; ++n)
|
||||
{
|
||||
if(strlen(RESVAR.dnsrch[n]) > 0)
|
||||
{
|
||||
jdns_string_t *str;
|
||||
jdns_string_t *p;
|
||||
str = jdns_string_new();
|
||||
jdns_string_set_cstr(str, RESVAR.dnsrch[n]);
|
||||
p = string_tolower(str);
|
||||
jdns_string_delete(str);
|
||||
str = p;
|
||||
|
||||
// don't add dups
|
||||
if(!dnsparams_have_domain(params, str))
|
||||
jdns_dnsparams_append_domain(params, str);
|
||||
|
||||
jdns_string_delete(str);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
static jdns_dnsparams_t *dnsparams_get_unix()
|
||||
{
|
||||
jdns_dnsparams_t *params;
|
||||
|
||||
// prefer system calls over files
|
||||
params = dnsparams_get_unixsys();
|
||||
if(params->nameservers->count == 0)
|
||||
{
|
||||
jdns_dnsparams_delete(params);
|
||||
params = dnsparams_get_unixfiles();
|
||||
}
|
||||
|
||||
apply_hosts_file(params, "/etc/hosts");
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
jdns_dnsparams_t *jdns_system_dnsparams()
|
||||
{
|
||||
#ifdef JDNS_OS_WIN
|
||||
return dnsparams_get_win();
|
||||
#else
|
||||
return dnsparams_get_unix();
|
||||
#endif
|
||||
}
|
||||
1471
iris-legacy/iris/irisnet/jdns/jdns_util.c
Normal file
1471
iris-legacy/iris/irisnet/jdns/jdns_util.c
Normal file
File diff suppressed because it is too large
Load diff
596
iris-legacy/iris/irisnet/jdns/main.cpp
Normal file
596
iris-legacy/iris/irisnet/jdns/main.cpp
Normal file
|
|
@ -0,0 +1,596 @@
|
|||
/*
|
||||
* Copyright (C) 2005 Justin Karneges
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtNetwork>
|
||||
#include "qjdns.h"
|
||||
|
||||
QString dataToString(const QByteArray &buf)
|
||||
{
|
||||
QString out;
|
||||
for(int n = 0; n < buf.size(); ++n)
|
||||
{
|
||||
unsigned char c = (unsigned char)buf[n];
|
||||
if(c == '\\')
|
||||
out += "\\\\";
|
||||
else if(c >= 0x20 && c < 0x7f)
|
||||
out += c;
|
||||
else
|
||||
out += QString().sprintf("\\x%02x", (unsigned int)c);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void print_record(const QJDns::Record &r)
|
||||
{
|
||||
switch(r.type)
|
||||
{
|
||||
case QJDns::A:
|
||||
printf(" A: [%s] (ttl=%d)\n", qPrintable(r.address.toString()), r.ttl);
|
||||
break;
|
||||
case QJDns::Aaaa:
|
||||
printf(" AAAA: [%s] (ttl=%d)\n", qPrintable(r.address.toString()), r.ttl);
|
||||
break;
|
||||
case QJDns::Mx:
|
||||
printf(" MX: [%s] priority=%d (ttl=%d)\n", r.name.data(), r.priority, r.ttl);
|
||||
break;
|
||||
case QJDns::Srv:
|
||||
printf(" SRV: [%s] port=%d priority=%d weight=%d (ttl=%d)\n", r.name.data(), r.port, r.priority, r.weight, r.ttl);
|
||||
break;
|
||||
case QJDns::Cname:
|
||||
printf(" CNAME: [%s] (ttl=%d)\n", r.name.data(), r.ttl);
|
||||
break;
|
||||
case QJDns::Ptr:
|
||||
printf(" PTR: [%s] (ttl=%d)\n", r.name.data(), r.ttl);
|
||||
break;
|
||||
case QJDns::Txt:
|
||||
{
|
||||
printf(" TXT: count=%d (ttl=%d)\n", r.texts.count(), r.ttl);
|
||||
for(int n = 0; n < r.texts.count(); ++n)
|
||||
printf(" len=%d [%s]\n", r.texts[n].size(), qPrintable(dataToString(r.texts[n])));
|
||||
break;
|
||||
}
|
||||
case QJDns::Hinfo:
|
||||
printf(" HINFO: [%s] [%s] (ttl=%d)\n", r.cpu.data(), r.os.data(), r.ttl);
|
||||
break;
|
||||
case QJDns::Ns:
|
||||
printf(" NS: [%s] (ttl=%d)\n", r.name.data(), r.ttl);
|
||||
break;
|
||||
default:
|
||||
printf(" (Unknown): type=%d, size=%d (ttl=%d)\n", r.type, r.rdata.size(), r.ttl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
class App : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
bool opt_debug, opt_ipv6, opt_quit;
|
||||
int quit_time;
|
||||
QString mode, type, name, ipaddr;
|
||||
QStringList nslist;
|
||||
QList<QJDns::Record> pubitems;
|
||||
QJDns jdns;
|
||||
int req_id;
|
||||
|
||||
App()
|
||||
{
|
||||
connect(&jdns, SIGNAL(resultsReady(int, const QJDns::Response &)), SLOT(jdns_resultsReady(int, const QJDns::Response &)));
|
||||
connect(&jdns, SIGNAL(published(int)), SLOT(jdns_published(int)));
|
||||
connect(&jdns, SIGNAL(error(int, QJDns::Error)), SLOT(jdns_error(int, QJDns::Error)));
|
||||
connect(&jdns, SIGNAL(shutdownFinished()), SLOT(jdns_shutdownFinished()));
|
||||
connect(&jdns, SIGNAL(debugLinesReady()), SLOT(jdns_debugLinesReady()));
|
||||
}
|
||||
|
||||
~App()
|
||||
{
|
||||
}
|
||||
|
||||
public slots:
|
||||
void start()
|
||||
{
|
||||
if(mode == "uni")
|
||||
{
|
||||
if(!jdns.init(QJDns::Unicast, opt_ipv6 ? QHostAddress::AnyIPv6 : QHostAddress::Any))
|
||||
{
|
||||
jdns_debugLinesReady();
|
||||
printf("unable to bind\n");
|
||||
emit quit();
|
||||
return;
|
||||
}
|
||||
|
||||
QList<QJDns::NameServer> addrs;
|
||||
for(int n = 0; n < nslist.count(); ++n)
|
||||
{
|
||||
QJDns::NameServer host;
|
||||
QString str = nslist[n];
|
||||
if(str == "mul")
|
||||
{
|
||||
if(opt_ipv6)
|
||||
host.address = QHostAddress("FF02::FB");
|
||||
else
|
||||
host.address = QHostAddress("224.0.0.251");
|
||||
host.port = 5353;
|
||||
}
|
||||
else
|
||||
{
|
||||
int at = str.indexOf(';');
|
||||
if(at != -1)
|
||||
{
|
||||
host.address = QHostAddress(str.mid(0, at));
|
||||
host.port = str.mid(at + 1).toInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
host.address = QHostAddress(str);
|
||||
}
|
||||
}
|
||||
|
||||
if(host.address.isNull() || host.port <= 0)
|
||||
{
|
||||
printf("bad nameserver: [%s]\n", qPrintable(nslist[n]));
|
||||
emit quit();
|
||||
return;
|
||||
}
|
||||
addrs += host;
|
||||
}
|
||||
|
||||
if(addrs.isEmpty())
|
||||
addrs = QJDns::systemInfo().nameServers;
|
||||
|
||||
if(addrs.isEmpty())
|
||||
{
|
||||
printf("no nameservers were detected or specified\n");
|
||||
emit quit();
|
||||
return;
|
||||
}
|
||||
|
||||
jdns.setNameServers(addrs);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!jdns.init(QJDns::Multicast, opt_ipv6 ? QHostAddress::AnyIPv6 : QHostAddress::Any))
|
||||
{
|
||||
jdns_debugLinesReady();
|
||||
printf("unable to bind\n");
|
||||
emit quit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == "uni" || mode == "mul")
|
||||
{
|
||||
int x = QJDns::A;
|
||||
if(type == "ptr")
|
||||
x = QJDns::Ptr;
|
||||
else if(type == "srv")
|
||||
x = QJDns::Srv;
|
||||
else if(type == "a")
|
||||
x = QJDns::A;
|
||||
else if(type == "aaaa")
|
||||
x = QJDns::Aaaa;
|
||||
else if(type == "mx")
|
||||
x = QJDns::Mx;
|
||||
else if(type == "txt")
|
||||
x = QJDns::Txt;
|
||||
else if(type == "hinfo")
|
||||
x = QJDns::Hinfo;
|
||||
else if(type == "cname")
|
||||
x = QJDns::Cname;
|
||||
else if(type == "any")
|
||||
x = QJDns::Any;
|
||||
else
|
||||
{
|
||||
bool ok;
|
||||
int y = type.toInt(&ok);
|
||||
if(ok)
|
||||
x = y;
|
||||
}
|
||||
|
||||
req_id = jdns.queryStart(name.toLatin1(), x);
|
||||
printf("[%d] Querying for [%s] type=%d ...\n", req_id, qPrintable(name), x);
|
||||
}
|
||||
else // publish
|
||||
{
|
||||
for(int n = 0; n < pubitems.count(); ++n)
|
||||
{
|
||||
const QJDns::Record &rr = pubitems[n];
|
||||
QJDns::PublishMode m = QJDns::Unique;
|
||||
if(rr.type == QJDns::Ptr)
|
||||
m = QJDns::Shared;
|
||||
int id = jdns.publishStart(m, rr);
|
||||
printf("[%d] Publishing [%s] type=%d ...\n", id, rr.owner.data(), rr.type);
|
||||
}
|
||||
}
|
||||
|
||||
if(opt_quit)
|
||||
QTimer::singleShot(quit_time * 1000, this, SLOT(doShutdown()));
|
||||
}
|
||||
|
||||
signals:
|
||||
void quit();
|
||||
|
||||
private slots:
|
||||
void jdns_resultsReady(int id, const QJDns::Response &results)
|
||||
{
|
||||
printf("[%d] Results\n", id);
|
||||
for(int n = 0; n < results.answerRecords.count(); ++n)
|
||||
print_record(results.answerRecords[n]);
|
||||
|
||||
if(mode == "uni")
|
||||
jdns.shutdown();
|
||||
}
|
||||
|
||||
void jdns_published(int id)
|
||||
{
|
||||
printf("[%d] Published\n", id);
|
||||
}
|
||||
|
||||
void jdns_error(int id, QJDns::Error e)
|
||||
{
|
||||
QString str;
|
||||
if(e == QJDns::ErrorGeneric)
|
||||
str = "Generic";
|
||||
else if(e == QJDns::ErrorNXDomain)
|
||||
str = "NXDomain";
|
||||
else if(e == QJDns::ErrorTimeout)
|
||||
str = "Timeout";
|
||||
else if(e == QJDns::ErrorConflict)
|
||||
str = "Conflict";
|
||||
printf("[%d] Error: %s\n", id, qPrintable(str));
|
||||
jdns.shutdown();
|
||||
}
|
||||
|
||||
void jdns_shutdownFinished()
|
||||
{
|
||||
emit quit();
|
||||
}
|
||||
|
||||
void jdns_debugLinesReady()
|
||||
{
|
||||
QStringList lines = jdns.debugLines();
|
||||
if(opt_debug)
|
||||
{
|
||||
for(int n = 0; n < lines.count(); ++n)
|
||||
printf("jdns: %s\n", qPrintable(lines[n]));
|
||||
}
|
||||
}
|
||||
|
||||
void doShutdown()
|
||||
{
|
||||
jdns.shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
#include "main.moc"
|
||||
|
||||
void usage()
|
||||
{
|
||||
printf("usage: jdns (options) uni [type] [name] (nameserver(;port)|mul ...)\n");
|
||||
printf(" jdns (options) mul [type] [name]\n");
|
||||
printf(" jdns (options) pub [items ...]\n");
|
||||
printf(" jdns sys\n");
|
||||
printf("\n");
|
||||
printf("options:\n");
|
||||
printf(" -d show debug output\n");
|
||||
printf(" -6 use ipv6\n");
|
||||
printf(" -q x quit x seconds after starting\n");
|
||||
printf("\n");
|
||||
printf("uni/mul types: a aaaa ptr srv mx txt hinfo cname any\n");
|
||||
printf("pub items: ptr:name,answer srv:name,answer,port a:name,ipaddr\n");
|
||||
printf(" txt:name,str0,...,strn aaaa:name,ipaddr\n");
|
||||
printf("\n");
|
||||
printf("examples:\n");
|
||||
printf(" jdns uni a jabber.org 192.168.0.1\n");
|
||||
printf(" jdns uni srv _xmpp-client._tcp.jabber.org 192.168.0.1;53\n");
|
||||
printf(" jdns uni 10 user@host._presence._tcp.local mul\n");
|
||||
printf(" jdns mul a foobar.local\n");
|
||||
printf(" jdns mul ptr _services._dns-sd._udp.local\n");
|
||||
printf(" jdns pub a:mybox.local.,192.168.0.55\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
if(argc < 2)
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// get args
|
||||
QStringList args;
|
||||
for(int n = 1; n < argc; ++n)
|
||||
args += QString(argv[n]);
|
||||
|
||||
bool opt_debug = false;
|
||||
bool opt_ipv6 = false;
|
||||
bool opt_quit = false;
|
||||
int quit_time = 0;
|
||||
QString mode, type, name, ipaddr;
|
||||
QStringList nslist;
|
||||
QList<QJDns::Record> pubitems;
|
||||
|
||||
// options
|
||||
for(int n = 0; n < args.count(); ++n)
|
||||
{
|
||||
if(args[n].left(1) == "-")
|
||||
{
|
||||
if(args[n] == "-d")
|
||||
opt_debug = true;
|
||||
else if(args[n] == "-6")
|
||||
opt_ipv6 = true;
|
||||
else if(args[n] == "-q")
|
||||
{
|
||||
if(n + 1 >= args.count())
|
||||
{
|
||||
printf("need to specify number of seconds\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int x = args[n + 1].toInt();
|
||||
if(x < 1)
|
||||
x = 30;
|
||||
|
||||
opt_quit = true;
|
||||
quit_time = x;
|
||||
|
||||
args.removeAt(n + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("bad option\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
args.removeAt(n);
|
||||
--n; // adjust position
|
||||
}
|
||||
}
|
||||
|
||||
mode = args[0];
|
||||
if(mode == "uni" || mode == "mul")
|
||||
{
|
||||
if(args.count() < 3)
|
||||
{
|
||||
printf("not enough args\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
type = args[1];
|
||||
name = args[2];
|
||||
if(mode == "uni")
|
||||
{
|
||||
for(int n = 3; n < args.count(); ++n)
|
||||
nslist += QString(args[n]);
|
||||
}
|
||||
}
|
||||
else if(mode == "pub")
|
||||
{
|
||||
if(args.count() < 2)
|
||||
{
|
||||
printf("not enough args\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
for(int n = 1; n < args.count(); ++n)
|
||||
{
|
||||
QString arg = args[n];
|
||||
int at = arg.indexOf(':');
|
||||
if(at == -1)
|
||||
{
|
||||
printf("missing colon\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
QString type = arg.mid(0, at).toLower();
|
||||
QString val = arg.mid(at + 1);
|
||||
if(type == "a")
|
||||
{
|
||||
QStringList list = val.split(',');
|
||||
if(list.count() != 2)
|
||||
{
|
||||
printf("bad format for A type\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
QHostAddress host(list[1]);
|
||||
if(host.isNull() || host.protocol() != QAbstractSocket::IPv4Protocol)
|
||||
{
|
||||
printf("bad format for A type IP address\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
QJDns::Record rec;
|
||||
rec.owner = list[0].toLatin1();
|
||||
rec.type = QJDns::A;
|
||||
rec.ttl = 120;
|
||||
rec.haveKnown = true;
|
||||
rec.address = host;
|
||||
pubitems += rec;
|
||||
}
|
||||
else if(type == "aaaa")
|
||||
{
|
||||
QStringList list = val.split(',');
|
||||
if(list.count() != 2)
|
||||
{
|
||||
printf("bad format for AAAA type\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
QHostAddress host(list[1]);
|
||||
if(host.isNull() || host.protocol() != QAbstractSocket::IPv6Protocol)
|
||||
{
|
||||
printf("bad format for AAAA type IP address\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
QJDns::Record rec;
|
||||
rec.owner = list[0].toLatin1();
|
||||
rec.type = QJDns::Aaaa;
|
||||
rec.ttl = 120;
|
||||
rec.haveKnown = true;
|
||||
rec.address = host;
|
||||
pubitems += rec;
|
||||
}
|
||||
else if(type == "srv")
|
||||
{
|
||||
QStringList list = val.split(',');
|
||||
if(list.count() != 3)
|
||||
{
|
||||
printf("bad format for SRV type\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
QJDns::Record rec;
|
||||
rec.owner = list[0].toLatin1();
|
||||
rec.type = QJDns::Srv;
|
||||
rec.ttl = 120;
|
||||
rec.haveKnown = true;
|
||||
rec.name = list[1].toLatin1();
|
||||
rec.priority = 0;
|
||||
rec.weight = 0;
|
||||
rec.port = list[2].toInt();
|
||||
pubitems += rec;
|
||||
}
|
||||
else if(type == "ptr")
|
||||
{
|
||||
QStringList list = val.split(',');
|
||||
if(list.count() != 2)
|
||||
{
|
||||
printf("bad format for PTR type\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
QJDns::Record rec;
|
||||
rec.owner = list[0].toLatin1();
|
||||
rec.type = QJDns::Ptr;
|
||||
rec.ttl = 120;
|
||||
rec.haveKnown = true;
|
||||
rec.name = list[1].toLatin1();
|
||||
pubitems += rec;
|
||||
}
|
||||
else if(type == "txt")
|
||||
{
|
||||
QStringList list = val.split(',');
|
||||
QList<QByteArray> texts;
|
||||
for(int n = 1; n < list.count(); ++n)
|
||||
texts += list[n].toLatin1();
|
||||
|
||||
QJDns::Record rec;
|
||||
rec.owner = list[0].toLatin1();
|
||||
rec.type = QJDns::Txt;
|
||||
rec.ttl = 120;
|
||||
rec.haveKnown = true;
|
||||
rec.texts = texts;
|
||||
pubitems += rec;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("bad record type [%s]\n", qPrintable(type));
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(mode == "sys")
|
||||
{
|
||||
QJDns::SystemInfo info = QJDns::systemInfo();
|
||||
|
||||
printf("DNS System Information\n");
|
||||
printf(" Name Servers:\n");
|
||||
if(!info.nameServers.isEmpty())
|
||||
{
|
||||
for(int n = 0; n < info.nameServers.count(); ++n)
|
||||
printf(" %s\n", qPrintable(info.nameServers[n].address.toString()));
|
||||
}
|
||||
else
|
||||
printf(" (None)\n");
|
||||
|
||||
printf(" Domains:\n");
|
||||
if(!info.domains.isEmpty())
|
||||
{
|
||||
for(int n = 0; n < info.domains.count(); ++n)
|
||||
printf(" [%s]\n", info.domains[n].data());
|
||||
}
|
||||
else
|
||||
printf(" (None)\n");
|
||||
|
||||
printf(" Hosts:\n");
|
||||
if(!info.hosts.isEmpty())
|
||||
{
|
||||
for(int n = 0; n < info.hosts.count(); ++n)
|
||||
{
|
||||
const QJDns::DnsHost &h = info.hosts[n];
|
||||
printf(" [%s] -> %s\n", h.name.data(), qPrintable(h.address.toString()));
|
||||
}
|
||||
}
|
||||
else
|
||||
printf(" (None)\n");
|
||||
|
||||
QHostAddress addr;
|
||||
printf("Primary IPv4 Multicast Address: ");
|
||||
addr = QJDns::detectPrimaryMulticast(QHostAddress::Any);
|
||||
if(!addr.isNull())
|
||||
printf("%s\n", qPrintable(addr.toString()));
|
||||
else
|
||||
printf("(None)\n");
|
||||
printf("Primary IPv6 Multicast Address: ");
|
||||
addr = QJDns::detectPrimaryMulticast(QHostAddress::AnyIPv6);
|
||||
if(!addr.isNull())
|
||||
printf("%s\n", qPrintable(addr.toString()));
|
||||
else
|
||||
printf("(None)\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
App a;
|
||||
a.opt_debug = opt_debug;
|
||||
a.opt_ipv6 = opt_ipv6;
|
||||
a.opt_quit = opt_quit;
|
||||
a.quit_time = quit_time;
|
||||
a.mode = mode;
|
||||
a.type = type.toLower();
|
||||
a.name = name;
|
||||
a.ipaddr = ipaddr;
|
||||
a.nslist = nslist;
|
||||
a.pubitems = pubitems;
|
||||
QObject::connect(&a, SIGNAL(quit()), &app, SLOT(quit()));
|
||||
QTimer::singleShot(0, &a, SLOT(start()));
|
||||
app.exec();
|
||||
return 0;
|
||||
}
|
||||
908
iris-legacy/iris/irisnet/jdns/qjdns.cpp
Normal file
908
iris-legacy/iris/irisnet/jdns/qjdns.cpp
Normal file
|
|
@ -0,0 +1,908 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qjdns.h"
|
||||
|
||||
#include <time.h>
|
||||
#include "qjdns_sock.h"
|
||||
#include "jdns.h"
|
||||
|
||||
static jdns_string_t *qt2str(const QByteArray &in)
|
||||
{
|
||||
jdns_string_t *out = jdns_string_new();
|
||||
jdns_string_set(out, (const unsigned char *)in.data(), in.size());
|
||||
return out;
|
||||
}
|
||||
|
||||
static QByteArray str2qt(const jdns_string_t *in)
|
||||
{
|
||||
return QByteArray((const char *)in->data, in->size);
|
||||
}
|
||||
|
||||
static void qt2addr_set(jdns_address_t *addr, const QHostAddress &host)
|
||||
{
|
||||
if(host.protocol() == QAbstractSocket::IPv6Protocol)
|
||||
jdns_address_set_ipv6(addr, host.toIPv6Address().c);
|
||||
else
|
||||
jdns_address_set_ipv4(addr, host.toIPv4Address());
|
||||
}
|
||||
|
||||
static jdns_address_t *qt2addr(const QHostAddress &host)
|
||||
{
|
||||
jdns_address_t *addr = jdns_address_new();
|
||||
qt2addr_set(addr, host);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static QHostAddress addr2qt(const jdns_address_t *addr)
|
||||
{
|
||||
if(addr->isIpv6)
|
||||
return QHostAddress(addr->addr.v6);
|
||||
else
|
||||
return QHostAddress(addr->addr.v4);
|
||||
}
|
||||
|
||||
static QJDns::Record import_record(const jdns_rr_t *in)
|
||||
{
|
||||
QJDns::Record out;
|
||||
|
||||
out.owner = QByteArray((const char *)in->owner);
|
||||
out.ttl = in->ttl;
|
||||
out.type = in->type;
|
||||
out.rdata = QByteArray((const char *)in->rdata, in->rdlength);
|
||||
|
||||
// known
|
||||
if(in->haveKnown)
|
||||
{
|
||||
int type = in->type;
|
||||
|
||||
if(type == QJDns::A || type == QJDns::Aaaa)
|
||||
{
|
||||
out.haveKnown = true;
|
||||
out.address = addr2qt(in->data.address);
|
||||
}
|
||||
else if(type == QJDns::Mx)
|
||||
{
|
||||
out.haveKnown = true;
|
||||
out.name = QByteArray((const char *)in->data.server->name);
|
||||
out.priority = in->data.server->priority;
|
||||
}
|
||||
else if(type == QJDns::Srv)
|
||||
{
|
||||
out.haveKnown = true;
|
||||
out.name = QByteArray((const char *)in->data.server->name);
|
||||
out.priority = in->data.server->priority;
|
||||
out.weight = in->data.server->weight;
|
||||
out.port = in->data.server->port;
|
||||
}
|
||||
else if(type == QJDns::Cname || type == QJDns::Ptr || type == QJDns::Ns)
|
||||
{
|
||||
out.haveKnown = true;
|
||||
out.name = QByteArray((const char *)in->data.name);
|
||||
}
|
||||
else if(type == QJDns::Txt)
|
||||
{
|
||||
out.haveKnown = true;
|
||||
out.texts.clear();
|
||||
for(int n = 0; n < in->data.texts->count; ++n)
|
||||
out.texts += str2qt(in->data.texts->item[n]);
|
||||
}
|
||||
else if(type == QJDns::Hinfo)
|
||||
{
|
||||
out.haveKnown = true;
|
||||
out.cpu = str2qt(in->data.hinfo.cpu);
|
||||
out.os = str2qt(in->data.hinfo.os);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static jdns_rr_t *export_record(const QJDns::Record &in)
|
||||
{
|
||||
jdns_rr_t *out = jdns_rr_new();
|
||||
|
||||
jdns_rr_set_owner(out, (const unsigned char *)in.owner.data());
|
||||
out->ttl = in.ttl;
|
||||
|
||||
// if we have known, use that
|
||||
if(in.haveKnown)
|
||||
{
|
||||
int type = in.type;
|
||||
|
||||
if(type == QJDns::A)
|
||||
{
|
||||
jdns_address_t *addr = qt2addr(in.address);
|
||||
jdns_rr_set_A(out, addr);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
else if(type == QJDns::Aaaa)
|
||||
{
|
||||
jdns_address_t *addr = qt2addr(in.address);
|
||||
jdns_rr_set_AAAA(out, addr);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
else if(type == QJDns::Mx)
|
||||
{
|
||||
jdns_rr_set_MX(out, (const unsigned char *)in.name.data(), in.priority);
|
||||
}
|
||||
else if(type == QJDns::Srv)
|
||||
{
|
||||
jdns_rr_set_SRV(out, (const unsigned char *)in.name.data(), in.port, in.priority, in.weight);
|
||||
}
|
||||
else if(type == QJDns::Cname)
|
||||
{
|
||||
jdns_rr_set_CNAME(out, (const unsigned char *)in.name.data());
|
||||
}
|
||||
else if(type == QJDns::Ptr)
|
||||
{
|
||||
jdns_rr_set_PTR(out, (const unsigned char *)in.name.data());
|
||||
}
|
||||
else if(type == QJDns::Txt)
|
||||
{
|
||||
jdns_stringlist_t *list = jdns_stringlist_new();
|
||||
for(int n = 0; n < in.texts.count(); ++n)
|
||||
{
|
||||
jdns_string_t *str = qt2str(in.texts[n]);
|
||||
jdns_stringlist_append(list, str);
|
||||
jdns_string_delete(str);
|
||||
}
|
||||
jdns_rr_set_TXT(out, list);
|
||||
jdns_stringlist_delete(list);
|
||||
}
|
||||
else if(type == QJDns::Hinfo)
|
||||
{
|
||||
jdns_string_t *cpu = qt2str(in.cpu);
|
||||
jdns_string_t *os = qt2str(in.os);
|
||||
jdns_rr_set_HINFO(out, cpu, os);
|
||||
jdns_string_delete(cpu);
|
||||
jdns_string_delete(os);
|
||||
}
|
||||
else if(type == QJDns::Ns)
|
||||
{
|
||||
jdns_rr_set_NS(out, (const unsigned char *)in.name.data());
|
||||
}
|
||||
}
|
||||
else
|
||||
jdns_rr_set_record(out, in.type, (const unsigned char *)in.rdata.data(), in.rdata.size());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// QJDns::NameServer
|
||||
//----------------------------------------------------------------------------
|
||||
QJDns::NameServer::NameServer()
|
||||
{
|
||||
port = JDNS_UNICAST_PORT;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// QJDns::Record
|
||||
//----------------------------------------------------------------------------
|
||||
QJDns::Record::Record()
|
||||
{
|
||||
ttl = 0;
|
||||
type = -1;
|
||||
haveKnown = false;
|
||||
}
|
||||
|
||||
bool QJDns::Record::verify() const
|
||||
{
|
||||
jdns_rr_t *rr = export_record(*this);
|
||||
int ok = jdns_rr_verify(rr);
|
||||
jdns_rr_delete(rr);
|
||||
return (ok ? true : false);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// QJDns
|
||||
//----------------------------------------------------------------------------
|
||||
static int my_srand_done = 0;
|
||||
|
||||
static void my_srand()
|
||||
{
|
||||
if(my_srand_done)
|
||||
return;
|
||||
|
||||
// lame attempt at randomizing without srand
|
||||
int count = ::time(NULL) % 128;
|
||||
for(int n = 0; n < count; ++n)
|
||||
rand();
|
||||
|
||||
my_srand_done = 1;
|
||||
}
|
||||
|
||||
class QJDns::Private : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
class LateError
|
||||
{
|
||||
public:
|
||||
int id;
|
||||
Error error;
|
||||
};
|
||||
|
||||
class LateResponse
|
||||
{
|
||||
public:
|
||||
int id;
|
||||
QJDns::Response response;
|
||||
};
|
||||
|
||||
QJDns *q;
|
||||
QJDns::Mode mode;
|
||||
jdns_session_t *sess;
|
||||
bool shutting_down;
|
||||
QTimer stepTrigger, debugTrigger;
|
||||
QTimer stepTimeout;
|
||||
QTime clock;
|
||||
QStringList debug_strings;
|
||||
bool new_debug_strings;
|
||||
int next_handle;
|
||||
bool need_handle;
|
||||
QHash<int,QUdpSocket*> socketForHandle;
|
||||
QHash<QUdpSocket*,int> handleForSocket;
|
||||
int pending;
|
||||
bool pending_wait;
|
||||
bool complete_shutdown;
|
||||
QList<LateError> lateErrors;
|
||||
|
||||
Private(QJDns *_q) : QObject(_q), q(_q), stepTrigger(this), debugTrigger(this), stepTimeout(this)
|
||||
{
|
||||
sess = 0;
|
||||
shutting_down = false;
|
||||
new_debug_strings = false;
|
||||
pending = 0;
|
||||
|
||||
connect(&stepTrigger, SIGNAL(timeout()), SLOT(doNextStepSlot()));
|
||||
stepTrigger.setSingleShot(true);
|
||||
|
||||
connect(&debugTrigger, SIGNAL(timeout()), SLOT(doDebug()));
|
||||
debugTrigger.setSingleShot(true);
|
||||
|
||||
connect(&stepTimeout, SIGNAL(timeout()), SLOT(st_timeout()));
|
||||
stepTimeout.setSingleShot(true);
|
||||
|
||||
my_srand();
|
||||
|
||||
clock.start();
|
||||
}
|
||||
|
||||
~Private()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
if(sess)
|
||||
{
|
||||
jdns_session_delete(sess);
|
||||
sess = 0;
|
||||
}
|
||||
shutting_down = false;
|
||||
pending = 0;
|
||||
qDeleteAll(socketForHandle);
|
||||
socketForHandle.clear();
|
||||
handleForSocket.clear();
|
||||
stepTrigger.stop();
|
||||
stepTimeout.stop();
|
||||
need_handle = 0;
|
||||
}
|
||||
|
||||
bool init(QJDns::Mode _mode, const QHostAddress &address)
|
||||
{
|
||||
mode = _mode;
|
||||
|
||||
jdns_callbacks_t callbacks;
|
||||
callbacks.app = this;
|
||||
callbacks.time_now = cb_time_now;
|
||||
callbacks.rand_int = cb_rand_int;
|
||||
callbacks.debug_line = cb_debug_line;
|
||||
callbacks.udp_bind = cb_udp_bind;
|
||||
callbacks.udp_unbind = cb_udp_unbind;
|
||||
callbacks.udp_read = cb_udp_read;
|
||||
callbacks.udp_write = cb_udp_write;
|
||||
sess = jdns_session_new(&callbacks);
|
||||
next_handle = 1;
|
||||
need_handle = false;
|
||||
|
||||
int ret;
|
||||
|
||||
jdns_address_t *baddr = qt2addr(address);
|
||||
if(mode == Unicast)
|
||||
{
|
||||
ret = jdns_init_unicast(sess, baddr, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
jdns_address_t *maddr;
|
||||
if(address.protocol() == QAbstractSocket::IPv6Protocol)
|
||||
maddr = jdns_address_multicast6_new();
|
||||
else
|
||||
maddr = jdns_address_multicast4_new();
|
||||
ret = jdns_init_multicast(sess, baddr, JDNS_MULTICAST_PORT, maddr);
|
||||
jdns_address_delete(maddr);
|
||||
}
|
||||
jdns_address_delete(baddr);
|
||||
|
||||
if(!ret)
|
||||
{
|
||||
jdns_session_delete(sess);
|
||||
sess = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void setNameServers(const QList<NameServer> &nslist)
|
||||
{
|
||||
jdns_nameserverlist_t *addrs = jdns_nameserverlist_new();
|
||||
for(int n = 0; n < nslist.count(); ++n)
|
||||
{
|
||||
jdns_address_t *addr = qt2addr(nslist[n].address);
|
||||
jdns_nameserverlist_append(addrs, addr, nslist[n].port);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
jdns_set_nameservers(sess, addrs);
|
||||
jdns_nameserverlist_delete(addrs);
|
||||
}
|
||||
|
||||
void process()
|
||||
{
|
||||
if(!stepTrigger.isActive())
|
||||
{
|
||||
stepTimeout.stop();
|
||||
stepTrigger.start();
|
||||
}
|
||||
}
|
||||
|
||||
void processDebug()
|
||||
{
|
||||
new_debug_strings = true;
|
||||
if(!debugTrigger.isActive())
|
||||
debugTrigger.start();
|
||||
}
|
||||
|
||||
void doNextStep()
|
||||
{
|
||||
if(shutting_down && complete_shutdown)
|
||||
{
|
||||
cleanup();
|
||||
emit q->shutdownFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
QPointer<QObject> self = this;
|
||||
|
||||
int ret = jdns_step(sess);
|
||||
|
||||
QList<LateError> errors;
|
||||
QList<int> published;
|
||||
QList<LateResponse> responses;
|
||||
bool finish_shutdown = false;
|
||||
|
||||
while(1)
|
||||
{
|
||||
jdns_event_t *e = jdns_next_event(sess);
|
||||
if(!e)
|
||||
break;
|
||||
|
||||
if(e->type == JDNS_EVENT_SHUTDOWN)
|
||||
{
|
||||
finish_shutdown = true;
|
||||
}
|
||||
else if(e->type == JDNS_EVENT_PUBLISH)
|
||||
{
|
||||
if(e->status != JDNS_STATUS_SUCCESS)
|
||||
{
|
||||
QJDns::Error error;
|
||||
if(e->status == JDNS_STATUS_CONFLICT)
|
||||
error = QJDns::ErrorConflict;
|
||||
else
|
||||
error = QJDns::ErrorGeneric;
|
||||
LateError le;
|
||||
le.id = e->id;
|
||||
le.error = error;
|
||||
errors += le;
|
||||
}
|
||||
else
|
||||
{
|
||||
published += e->id;
|
||||
}
|
||||
}
|
||||
else if(e->type == JDNS_EVENT_RESPONSE)
|
||||
{
|
||||
if(e->status != JDNS_STATUS_SUCCESS)
|
||||
{
|
||||
QJDns::Error error;
|
||||
if(e->status == JDNS_STATUS_NXDOMAIN)
|
||||
error = QJDns::ErrorNXDomain;
|
||||
else if(e->status == JDNS_STATUS_TIMEOUT)
|
||||
error = QJDns::ErrorTimeout;
|
||||
else
|
||||
error = QJDns::ErrorGeneric;
|
||||
LateError le;
|
||||
le.id = e->id;
|
||||
le.error = error;
|
||||
errors += le;
|
||||
}
|
||||
else
|
||||
{
|
||||
QJDns::Response out_response;
|
||||
for(int n = 0; n < e->response->answerCount; ++n)
|
||||
out_response.answerRecords += import_record(e->response->answerRecords[n]);
|
||||
LateResponse lr;
|
||||
lr.id = e->id;
|
||||
lr.response = out_response;
|
||||
responses += lr;
|
||||
}
|
||||
}
|
||||
|
||||
jdns_event_delete(e);
|
||||
}
|
||||
|
||||
if(ret & JDNS_STEP_TIMER)
|
||||
stepTimeout.start(jdns_next_timer(sess));
|
||||
else
|
||||
stepTimeout.stop();
|
||||
|
||||
need_handle = (ret & JDNS_STEP_HANDLE);
|
||||
|
||||
for(int n = 0; n < errors.count(); ++n)
|
||||
{
|
||||
emit q->error(errors[n].id, errors[n].error);
|
||||
if(!self)
|
||||
return;
|
||||
}
|
||||
|
||||
for(int n = 0; n < published.count(); ++n)
|
||||
{
|
||||
emit q->published(published[n]);
|
||||
if(!self)
|
||||
return;
|
||||
}
|
||||
|
||||
for(int n = 0; n < responses.count(); ++n)
|
||||
{
|
||||
emit q->resultsReady(responses[n].id, responses[n].response);
|
||||
if(!self)
|
||||
return;
|
||||
}
|
||||
|
||||
if(finish_shutdown)
|
||||
{
|
||||
// if we have pending udp packets to write, stick around
|
||||
if(pending > 0)
|
||||
{
|
||||
pending_wait = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
complete_shutdown = true;
|
||||
process();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private slots:
|
||||
void udp_readyRead()
|
||||
{
|
||||
QUdpSocket *sock = (QUdpSocket *)sender();
|
||||
int handle = handleForSocket.value(sock);
|
||||
|
||||
if(need_handle)
|
||||
{
|
||||
jdns_set_handle_readable(sess, handle);
|
||||
process();
|
||||
}
|
||||
else
|
||||
{
|
||||
// eat packet
|
||||
QByteArray buf(4096, 0);
|
||||
QHostAddress from_addr;
|
||||
quint16 from_port;
|
||||
sock->readDatagram(buf.data(), buf.size(), &from_addr, &from_port);
|
||||
}
|
||||
}
|
||||
|
||||
void udp_bytesWritten(qint64)
|
||||
{
|
||||
if(pending > 0)
|
||||
{
|
||||
--pending;
|
||||
if(shutting_down && pending_wait && pending == 0)
|
||||
{
|
||||
pending_wait = false;
|
||||
complete_shutdown = true;
|
||||
process();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void st_timeout()
|
||||
{
|
||||
doNextStep();
|
||||
}
|
||||
|
||||
void doNextStepSlot()
|
||||
{
|
||||
doNextStep();
|
||||
}
|
||||
|
||||
void doDebug()
|
||||
{
|
||||
if(new_debug_strings)
|
||||
{
|
||||
new_debug_strings = false;
|
||||
if(!debug_strings.isEmpty())
|
||||
emit q->debugLinesReady();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// jdns callbacks
|
||||
static int cb_time_now(jdns_session_t *, void *app)
|
||||
{
|
||||
QJDns::Private *self = (QJDns::Private *)app;
|
||||
|
||||
return self->clock.elapsed();
|
||||
}
|
||||
|
||||
static int cb_rand_int(jdns_session_t *, void *)
|
||||
{
|
||||
return rand() % 65536;
|
||||
}
|
||||
|
||||
static void cb_debug_line(jdns_session_t *, void *app, const char *str)
|
||||
{
|
||||
QJDns::Private *self = (QJDns::Private *)app;
|
||||
|
||||
self->debug_strings += QString::fromLatin1(str);
|
||||
self->processDebug();
|
||||
}
|
||||
|
||||
static int cb_udp_bind(jdns_session_t *, void *app, const jdns_address_t *addr, int port, const jdns_address_t *maddr)
|
||||
{
|
||||
QJDns::Private *self = (QJDns::Private *)app;
|
||||
|
||||
// we always pass non-null to jdns_init, so this should be a valid address
|
||||
QHostAddress host = addr2qt(addr);
|
||||
|
||||
QUdpSocket *sock = new QUdpSocket(self);
|
||||
self->connect(sock, SIGNAL(readyRead()), SLOT(udp_readyRead()));
|
||||
|
||||
// use queued for bytesWritten, since qt is evil and emits before writeDatagram returns
|
||||
qRegisterMetaType<qint64>("qint64");
|
||||
self->connect(sock, SIGNAL(bytesWritten(qint64)), SLOT(udp_bytesWritten(qint64)), Qt::QueuedConnection);
|
||||
|
||||
QUdpSocket::BindMode mode;
|
||||
mode |= QUdpSocket::ShareAddress;
|
||||
mode |= QUdpSocket::ReuseAddressHint;
|
||||
if(!sock->bind(host, port, mode))
|
||||
{
|
||||
delete sock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(maddr)
|
||||
{
|
||||
int sd = sock->socketDescriptor();
|
||||
bool ok;
|
||||
int errorCode;
|
||||
if(maddr->isIpv6)
|
||||
ok = qjdns_sock_setMulticast6(sd, maddr->addr.v6, &errorCode);
|
||||
else
|
||||
ok = qjdns_sock_setMulticast4(sd, maddr->addr.v4, &errorCode);
|
||||
|
||||
if(!ok)
|
||||
{
|
||||
delete sock;
|
||||
|
||||
self->debug_strings += QString("failed to setup multicast on the socket (errorCode=%1)").arg(errorCode);
|
||||
self->processDebug();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(maddr->isIpv6)
|
||||
{
|
||||
qjdns_sock_setTTL6(sd, 255);
|
||||
qjdns_sock_setIPv6Only(sd);
|
||||
}
|
||||
else
|
||||
qjdns_sock_setTTL4(sd, 255);
|
||||
}
|
||||
|
||||
int handle = self->next_handle++;
|
||||
self->socketForHandle.insert(handle, sock);
|
||||
self->handleForSocket.insert(sock, handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void cb_udp_unbind(jdns_session_t *, void *app, int handle)
|
||||
{
|
||||
QJDns::Private *self = (QJDns::Private *)app;
|
||||
|
||||
QUdpSocket *sock = self->socketForHandle.value(handle);
|
||||
if(!sock)
|
||||
return;
|
||||
|
||||
self->socketForHandle.remove(handle);
|
||||
self->handleForSocket.remove(sock);
|
||||
delete sock;
|
||||
}
|
||||
|
||||
static int cb_udp_read(jdns_session_t *, void *app, int handle, jdns_address_t *addr, int *port, unsigned char *buf, int *bufsize)
|
||||
{
|
||||
QJDns::Private *self = (QJDns::Private *)app;
|
||||
|
||||
QUdpSocket *sock = self->socketForHandle.value(handle);
|
||||
if(!sock)
|
||||
return 0;
|
||||
|
||||
// nothing to read?
|
||||
if(!sock->hasPendingDatagrams())
|
||||
return 0;
|
||||
|
||||
QHostAddress from_addr;
|
||||
quint16 from_port;
|
||||
int ret = sock->readDatagram((char *)buf, *bufsize, &from_addr, &from_port);
|
||||
if(ret == -1)
|
||||
return 0;
|
||||
|
||||
qt2addr_set(addr, from_addr);
|
||||
*port = (int)from_port;
|
||||
*bufsize = ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cb_udp_write(jdns_session_t *, void *app, int handle, const jdns_address_t *addr, int port, unsigned char *buf, int bufsize)
|
||||
{
|
||||
QJDns::Private *self = (QJDns::Private *)app;
|
||||
|
||||
QUdpSocket *sock = self->socketForHandle.value(handle);
|
||||
if(!sock)
|
||||
return 0;
|
||||
|
||||
QHostAddress host = addr2qt(addr);
|
||||
int ret = sock->writeDatagram((const char *)buf, bufsize, host, port);
|
||||
if(ret == -1)
|
||||
{
|
||||
// this can happen if the datagram to send is too big. i'm not sure what else
|
||||
// may cause this. if we return 0, then jdns may try to resend the packet,
|
||||
// which might not work if it is too large (causing the same error over and
|
||||
// over). we'll return success to jdns, so the result is as if the packet
|
||||
// was dropped.
|
||||
return 1;
|
||||
}
|
||||
|
||||
++self->pending;
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
QJDns::QJDns(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
d = new Private(this);
|
||||
}
|
||||
|
||||
QJDns::~QJDns()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool QJDns::init(Mode mode, const QHostAddress &address)
|
||||
{
|
||||
return d->init(mode, address);
|
||||
}
|
||||
|
||||
void QJDns::shutdown()
|
||||
{
|
||||
d->shutting_down = true;
|
||||
d->pending_wait = false;
|
||||
d->complete_shutdown = false;
|
||||
jdns_shutdown(d->sess);
|
||||
d->process();
|
||||
}
|
||||
|
||||
QStringList QJDns::debugLines()
|
||||
{
|
||||
QStringList tmp = d->debug_strings;
|
||||
d->debug_strings.clear();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
QJDns::SystemInfo QJDns::systemInfo()
|
||||
{
|
||||
SystemInfo out;
|
||||
jdns_dnsparams_t *params = jdns_system_dnsparams();
|
||||
for(int n = 0; n < params->nameservers->count; ++n)
|
||||
{
|
||||
NameServer ns;
|
||||
ns.address = addr2qt(params->nameservers->item[n]->address);
|
||||
out.nameServers += ns;
|
||||
}
|
||||
for(int n = 0; n < params->domains->count; ++n)
|
||||
out.domains += str2qt(params->domains->item[n]);
|
||||
for(int n = 0; n < params->hosts->count; ++n)
|
||||
{
|
||||
DnsHost h;
|
||||
h.name = str2qt(params->hosts->item[n]->name);
|
||||
h.address = addr2qt(params->hosts->item[n]->address);
|
||||
out.hosts += h;
|
||||
}
|
||||
jdns_dnsparams_delete(params);
|
||||
return out;
|
||||
}
|
||||
|
||||
#define PROBE_BASE 20000
|
||||
#define PROBE_RANGE 100
|
||||
|
||||
QHostAddress QJDns::detectPrimaryMulticast(const QHostAddress &address)
|
||||
{
|
||||
my_srand();
|
||||
|
||||
QUdpSocket *sock = new QUdpSocket;
|
||||
QUdpSocket::BindMode mode;
|
||||
mode |= QUdpSocket::ShareAddress;
|
||||
mode |= QUdpSocket::ReuseAddressHint;
|
||||
int port = -1;
|
||||
for(int n = 0; n < PROBE_RANGE; ++n)
|
||||
{
|
||||
if(sock->bind(address, PROBE_BASE + n, mode))
|
||||
{
|
||||
port = PROBE_BASE + n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(port == -1)
|
||||
{
|
||||
delete sock;
|
||||
return QHostAddress();
|
||||
}
|
||||
|
||||
jdns_address_t *a;
|
||||
if(address.protocol() == QAbstractSocket::IPv6Protocol)
|
||||
a = jdns_address_multicast6_new();
|
||||
else
|
||||
a = jdns_address_multicast4_new();
|
||||
QHostAddress maddr = addr2qt(a);
|
||||
jdns_address_delete(a);
|
||||
|
||||
if(address.protocol() == QAbstractSocket::IPv6Protocol)
|
||||
{
|
||||
int x;
|
||||
if(!qjdns_sock_setMulticast6(sock->socketDescriptor(), maddr.toIPv6Address().c, &x))
|
||||
{
|
||||
delete sock;
|
||||
return QHostAddress();
|
||||
}
|
||||
qjdns_sock_setTTL6(sock->socketDescriptor(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int x;
|
||||
if(!qjdns_sock_setMulticast4(sock->socketDescriptor(), maddr.toIPv4Address(), &x))
|
||||
{
|
||||
delete sock;
|
||||
return QHostAddress();
|
||||
}
|
||||
qjdns_sock_setTTL4(sock->socketDescriptor(), 0);
|
||||
}
|
||||
|
||||
QHostAddress result;
|
||||
QByteArray out(128, 0);
|
||||
for(int n = 0; n < out.size(); ++n)
|
||||
out[n] = rand();
|
||||
if(sock->writeDatagram(out.data(), out.size(), maddr, port) == -1)
|
||||
{
|
||||
delete sock;
|
||||
return QHostAddress();
|
||||
}
|
||||
while(1)
|
||||
{
|
||||
sock->waitForReadyRead(-1);
|
||||
QByteArray in(128, 0);
|
||||
QHostAddress from_addr;
|
||||
quint16 from_port;
|
||||
int ret = sock->readDatagram(in.data(), in.size(), &from_addr, &from_port);
|
||||
if(ret == -1)
|
||||
continue;
|
||||
if(from_port != port)
|
||||
continue;
|
||||
in.resize(ret);
|
||||
if(in.size() != out.size())
|
||||
continue;
|
||||
bool ok = true;
|
||||
for(int n = 0; n < in.size(); ++n)
|
||||
{
|
||||
if(in[n] != out[n])
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!ok)
|
||||
continue;
|
||||
|
||||
result = from_addr;
|
||||
break;
|
||||
}
|
||||
delete sock;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void QJDns::setNameServers(const QList<NameServer> &list)
|
||||
{
|
||||
d->setNameServers(list);
|
||||
}
|
||||
|
||||
int QJDns::queryStart(const QByteArray &name, int type)
|
||||
{
|
||||
int id = jdns_query(d->sess, (const unsigned char *)name.data(), type);
|
||||
d->process();
|
||||
return id;
|
||||
}
|
||||
|
||||
void QJDns::queryCancel(int id)
|
||||
{
|
||||
jdns_cancel_query(d->sess, id);
|
||||
d->process();
|
||||
}
|
||||
|
||||
int QJDns::publishStart(PublishMode m, const Record &record)
|
||||
{
|
||||
jdns_rr_t *rr = export_record(record);
|
||||
|
||||
int pubmode;
|
||||
if(m == QJDns::Unique)
|
||||
pubmode = JDNS_PUBLISH_UNIQUE;
|
||||
else
|
||||
pubmode = JDNS_PUBLISH_SHARED;
|
||||
|
||||
int id = jdns_publish(d->sess, pubmode, rr);
|
||||
jdns_rr_delete(rr);
|
||||
d->process();
|
||||
return id;
|
||||
}
|
||||
|
||||
void QJDns::publishUpdate(int id, const Record &record)
|
||||
{
|
||||
jdns_rr_t *rr = export_record(record);
|
||||
|
||||
jdns_update_publish(d->sess, id, rr);
|
||||
jdns_rr_delete(rr);
|
||||
d->process();
|
||||
}
|
||||
|
||||
void QJDns::publishCancel(int id)
|
||||
{
|
||||
jdns_cancel_publish(d->sess, id);
|
||||
d->process();
|
||||
}
|
||||
|
||||
#include "qjdns.moc"
|
||||
158
iris-legacy/iris/irisnet/jdns/qjdns.h
Normal file
158
iris-legacy/iris/irisnet/jdns/qjdns.h
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// this is the Qt wrapper to jdns. it requires Qt 4.1+
|
||||
|
||||
#ifndef QJDNS_H
|
||||
#define QJDNS_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtNetwork>
|
||||
|
||||
class QJDns : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Mode
|
||||
{
|
||||
Unicast,
|
||||
Multicast
|
||||
};
|
||||
|
||||
enum PublishMode
|
||||
{
|
||||
Unique,
|
||||
Shared
|
||||
};
|
||||
|
||||
enum Type
|
||||
{
|
||||
A = 1,
|
||||
Aaaa = 28,
|
||||
Mx = 15,
|
||||
Srv = 33,
|
||||
Cname = 5,
|
||||
Ptr = 12,
|
||||
Txt = 16,
|
||||
Hinfo = 13,
|
||||
Ns = 2,
|
||||
Any = 255
|
||||
};
|
||||
|
||||
enum Error
|
||||
{
|
||||
ErrorGeneric,
|
||||
ErrorNXDomain, // query only
|
||||
ErrorTimeout, // query only
|
||||
ErrorConflict // publish only
|
||||
};
|
||||
|
||||
class NameServer
|
||||
{
|
||||
public:
|
||||
QHostAddress address;
|
||||
int port;
|
||||
|
||||
NameServer();
|
||||
};
|
||||
|
||||
class DnsHost
|
||||
{
|
||||
public:
|
||||
QByteArray name;
|
||||
QHostAddress address;
|
||||
};
|
||||
|
||||
class SystemInfo
|
||||
{
|
||||
public:
|
||||
QList<NameServer> nameServers;
|
||||
QList<QByteArray> domains;
|
||||
QList<DnsHost> hosts;
|
||||
};
|
||||
|
||||
class Record
|
||||
{
|
||||
public:
|
||||
QByteArray owner;
|
||||
int ttl;
|
||||
int type;
|
||||
QByteArray rdata;
|
||||
bool haveKnown;
|
||||
|
||||
// known
|
||||
QHostAddress address; // for A, Aaaa
|
||||
QByteArray name; // for Mx, Srv, Cname, Ptr, Ns
|
||||
int priority; // for Mx, Srv
|
||||
int weight; // for Srv
|
||||
int port; // for Srv
|
||||
QList<QByteArray> texts; // for Txt
|
||||
QByteArray cpu; // for Hinfo
|
||||
QByteArray os; // for Hinfo
|
||||
|
||||
Record();
|
||||
bool verify() const;
|
||||
};
|
||||
|
||||
class Response
|
||||
{
|
||||
public:
|
||||
QList<Record> answerRecords;
|
||||
QList<Record> authorityRecords;
|
||||
QList<Record> additionalRecords;
|
||||
};
|
||||
|
||||
QJDns(QObject *parent = 0);
|
||||
~QJDns();
|
||||
|
||||
bool init(Mode mode, const QHostAddress &address);
|
||||
void shutdown();
|
||||
QStringList debugLines();
|
||||
|
||||
static SystemInfo systemInfo();
|
||||
static QHostAddress detectPrimaryMulticast(const QHostAddress &address);
|
||||
|
||||
void setNameServers(const QList<NameServer> &list);
|
||||
|
||||
int queryStart(const QByteArray &name, int type);
|
||||
void queryCancel(int id);
|
||||
|
||||
// for multicast mode only
|
||||
int publishStart(PublishMode m, const Record &record);
|
||||
void publishUpdate(int id, const Record &record);
|
||||
void publishCancel(int id);
|
||||
|
||||
signals:
|
||||
void resultsReady(int id, const QJDns::Response &results);
|
||||
void published(int id);
|
||||
void error(int id, QJDns::Error e);
|
||||
void shutdownFinished();
|
||||
void debugLinesReady();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
friend class Private;
|
||||
Private *d;
|
||||
};
|
||||
|
||||
#endif
|
||||
184
iris-legacy/iris/irisnet/jdns/qjdns_sock.cpp
Normal file
184
iris-legacy/iris/irisnet/jdns/qjdns_sock.cpp
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qjdns_sock.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <winsock2.h>
|
||||
# include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
# include <sys/time.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <fcntl.h>
|
||||
# include <errno.h>
|
||||
# include <signal.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifndef QT_NO_IPV6
|
||||
# define HAVE_IPV6
|
||||
# ifndef IPPROTO_IPV6
|
||||
# define IPPROTO_IPV6 41
|
||||
struct in6_addr
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned char _S6_u8[16];
|
||||
unsigned short _S6_u16[8];
|
||||
unsigned long _S6_u32[4];
|
||||
} _S6_un;
|
||||
};
|
||||
# define s6_addr _S6_un._S6_u8
|
||||
# endif
|
||||
# ifndef IPV6_JOIN_GROUP
|
||||
# define IPV6_JOIN_GROUP 12
|
||||
# define IPV6_MULTICAST_HOPS 10
|
||||
struct ipv6_mreq
|
||||
{
|
||||
struct in6_addr ipv6mr_multiaddr;
|
||||
unsigned int ipv6mr_interface;
|
||||
};
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static int get_last_error()
|
||||
{
|
||||
int x;
|
||||
#ifdef Q_OS_WIN
|
||||
x = WSAGetLastError();
|
||||
#else
|
||||
x = errno;
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
|
||||
bool qjdns_sock_setMulticast4(int s, unsigned long int addr, int *errorCode)
|
||||
{
|
||||
int ret;
|
||||
struct ip_mreq mc;
|
||||
|
||||
memset(&mc, 0, sizeof(mc));
|
||||
mc.imr_multiaddr.s_addr = htonl(addr);
|
||||
mc.imr_interface.s_addr = INADDR_ANY;
|
||||
|
||||
ret = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&mc, sizeof(mc));
|
||||
if(ret != 0)
|
||||
{
|
||||
if(errorCode)
|
||||
*errorCode = get_last_error();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qjdns_sock_setMulticast6(int s, unsigned char *addr, int *errorCode)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
int ret;
|
||||
struct ipv6_mreq mc;
|
||||
|
||||
memset(&mc, 0, sizeof(mc));
|
||||
memcpy(mc.ipv6mr_multiaddr.s6_addr, addr, 16);
|
||||
mc.ipv6mr_interface = 0;
|
||||
|
||||
ret = setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, (const char *)&mc, sizeof(mc));
|
||||
if(ret != 0)
|
||||
{
|
||||
if(errorCode)
|
||||
*errorCode = get_last_error();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
Q_UNUSED(s);
|
||||
Q_UNUSED(addr);
|
||||
Q_UNUSED(errorCode);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool qjdns_sock_setTTL4(int s, int ttl)
|
||||
{
|
||||
unsigned char cttl;
|
||||
int ret, ittl;
|
||||
|
||||
cttl = ttl;
|
||||
ittl = ttl;
|
||||
|
||||
// IP_MULTICAST_TTL might take 1 byte or 4, try both
|
||||
ret = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&cttl, sizeof(cttl));
|
||||
if(ret != 0)
|
||||
{
|
||||
ret = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&ittl, sizeof(ittl));
|
||||
if(ret != 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qjdns_sock_setTTL6(int s, int ttl)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
unsigned char cttl;
|
||||
int ret, ittl;
|
||||
|
||||
cttl = ttl;
|
||||
ittl = ttl;
|
||||
|
||||
// IPV6_MULTICAST_HOPS might take 1 byte or 4, try both
|
||||
ret = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char *)&cttl, sizeof(cttl));
|
||||
if(ret != 0)
|
||||
{
|
||||
ret = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char *)&ittl, sizeof(ittl));
|
||||
if(ret != 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
Q_UNUSED(s);
|
||||
Q_UNUSED(ttl);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool qjdns_sock_setIPv6Only(int s)
|
||||
{
|
||||
#if defined(HAVE_IPV6) && defined(IPV6_V6ONLY)
|
||||
int x = 1;
|
||||
if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&x, sizeof(x)) != 0)
|
||||
return false;
|
||||
return true;
|
||||
#else
|
||||
Q_UNUSED(s);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
33
iris-legacy/iris/irisnet/jdns/qjdns_sock.h
Normal file
33
iris-legacy/iris/irisnet/jdns/qjdns_sock.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QJDNS_SOCK_H
|
||||
#define QJDNS_SOCK_H
|
||||
|
||||
bool qjdns_sock_setMulticast4(int s, unsigned long int addr, int *errorCode);
|
||||
bool qjdns_sock_setMulticast6(int s, unsigned char *addr, int *errorCode);
|
||||
bool qjdns_sock_setTTL4(int s, int ttl);
|
||||
bool qjdns_sock_setTTL6(int s, int ttl);
|
||||
bool qjdns_sock_setIPv6Only(int s);
|
||||
|
||||
#endif
|
||||
Reference in a new issue