aboutsummaryrefslogtreecommitdiffstats
path: root/src/lua/lua_dns.c
blob: 79ec72f9446f2ed4fd6b73f61aa178ee9ba6ba92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*-
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "lua_common.h"
#include "lua_dns_resolver.h"
#include "lua_thread_pool.h"

LUA_FUNCTION_DEF (dns, request);

static const struct luaL_reg dns_f[] = {
		LUA_INTERFACE_DEF (dns, request),
		{"__tostring", rspamd_lua_class_tostring},
		{NULL, NULL}
};

static const gchar *M = "rspamd lua dns";

void lua_dns_callback (struct rdns_reply *reply, void *arg);

struct lua_rspamd_dns_cbdata {
	struct thread_entry *thread;
	struct rspamd_task *task;
	struct rspamd_dns_resolver *resolver;
	struct rspamd_symcache_dynamic_item *item;
	struct rspamd_async_session *s;
};

static gint
lua_dns_request (lua_State *L)
{
	GError *err = NULL;
	struct rspamd_async_session *session = NULL;
	struct rspamd_config *cfg = NULL;
	struct lua_rspamd_dns_cbdata *cbdata = NULL;
	const gchar *to_resolve = NULL;
	const gchar *type_str = NULL;
	struct rspamd_task *task = NULL;
	rspamd_mempool_t *pool = NULL;
	gint ret = 0;
	gboolean forced = FALSE;

	/* Check arguments */
	if (!rspamd_lua_parse_table_arguments (L, 1, &err,
			RSPAMD_LUA_PARSE_ARGUMENTS_DEFAULT,
			"*name=S;task=U{task};*type=S;forced=B;session=U{session};config=U{config}",
			&to_resolve,
			&task,
			&type_str,
			&forced,
			&session,
			&cfg)) {

		if (err) {
			ret = luaL_error (L, "invalid arguments: %s", err->message);
			g_error_free (err);

			return ret;
		}

		return luaL_error (L, "invalid arguments");
	}

	if (task) {
		session = task->s;
		pool = task->task_pool;
		cfg = task->cfg;
	}
	else if (session && cfg) {
		pool = cfg->cfg_pool;
	}
	else {
		return luaL_error (L, "invalid arguments: either task or session/config should be set");
	}

	enum rdns_request_type type = rdns_type_fromstr (type_str);

	if (type == RDNS_REQUEST_INVALID) {
		return luaL_error (L, "invalid arguments: this record type is not supported");
	}

	cbdata = rspamd_mempool_alloc0 (pool, sizeof (*cbdata));

	cbdata->task = task;

	if (type == RDNS_REQUEST_PTR) {
		char *ptr_str;

		ptr_str = rdns_generate_ptr_from_str (to_resolve);

		if (ptr_str == NULL) {
			msg_err_task_check ("wrong resolve string to PTR request: %s",
								to_resolve);
			lua_pushnil (L);

			return 1;
		}

		to_resolve = rspamd_mempool_strdup (pool, ptr_str);
		free (ptr_str);
	}


	if (task == NULL) {
		ret = (rspamd_dns_resolver_request (cfg->dns_resolver,
				session,
				pool,
				lua_dns_callback,
				cbdata,
				type,
				to_resolve) != NULL);
	}
	else {
		if (forced) {
			ret = rspamd_dns_resolver_request_task_forced (task,
					lua_dns_callback,
					cbdata,
					type,
					to_resolve);
		}
		else {
			ret = rspamd_dns_resolver_request_task (task,
					lua_dns_callback,
					cbdata,
					type,
					to_resolve);
		}
	}

	if (ret) {
		cbdata->thread = lua_thread_pool_get_running_entry (cfg->lua_thread_pool);
		cbdata->s = session;

		if (task) {
			cbdata->item = rspamd_symcache_get_cur_item (task);
			rspamd_symcache_item_async_inc (task, cbdata->item, M);
		}

		return lua_thread_yield (cbdata->thread, 0);
	}
	else {
		lua_pushnil (L);
		return 1;
	}
}

void
lua_dns_callback (struct rdns_reply *reply, void *arg)
{
	struct lua_rspamd_dns_cbdata *cbdata = arg;
	lua_State *L = cbdata->thread->lua_state;

	if (reply->code != RDNS_RC_NOERROR) {
		lua_pushboolean (L, false);
		lua_pushstring (L, rdns_strerror (reply->code));
	}
	else {
		lua_push_dns_reply (L, reply);

		lua_pushboolean (L, reply->flags & RDNS_AUTH);
		lua_setfield (L, -3, "authenticated");

		lua_pushboolean (L, reply->flags & RDNS_TRUNCATED);
		lua_setfield (L, -3, "truncated");

		/* result 1 - not and error */
		lua_pushboolean (L, true);
		/* push table into stack, result 2 - results itself */
		lua_pushvalue (L, -3);
	}

	lua_thread_resume (cbdata->thread, 2);

	if (cbdata->item) {
		rspamd_symcache_item_async_dec_check (cbdata->task, cbdata->item, M);
	}
}

static gint
lua_load_dns (lua_State *L)
{
	lua_newtable (L);
	luaL_register (L, NULL, dns_f);

	return 1;
}

void
luaopen_dns (lua_State *L)
{
	rspamd_lua_add_preload (L, "rspamd_dns", lua_load_dns);
}
n class="p">} /** * Tests whether the user is using Chrome. * * @return true if the user is using Chrome, false if the user is not using * Chrome or if no information on the browser is present */ public boolean isChrome() { if (browserDetails == null) { return false; } return browserDetails.isChrome(); } /** * Tests whether the user is using Chrome Frame. * * @return true if the user is using Chrome Frame, false if the user is not * using Chrome or if no information on the browser is present */ public boolean isChromeFrame() { if (browserDetails == null) { return false; } return browserDetails.isChromeFrame(); } /** * Tests whether the user's browser is Chrome Frame capable. * * @return true if the user can use Chrome Frame, false if the user can not * or if no information on the browser is present */ public boolean isChromeFrameCapable() { if (browserDetails == null) { return false; } return browserDetails.isChromeFrameCapable(); } /** * Gets the major version of the browser the user is using. * * <p> * Note that Internet Explorer in IE7 compatibility mode might return 8 in * some cases even though it should return 7. * </p> * * @return The major version of the browser or -1 if not known. */ public int getBrowserMajorVersion() { if (browserDetails == null) { return -1; } return browserDetails.getBrowserMajorVersion(); } /** * Gets the minor version of the browser the user is using. * * @see #getBrowserMajorVersion() * * @return The minor version of the browser or -1 if not known. */ public int getBrowserMinorVersion() { if (browserDetails == null) { return -1; } return browserDetails.getBrowserMinorVersion(); } /** * Tests whether the user is using Linux. * * @return true if the user is using Linux, false if the user is not using * Linux or if no information on the browser is present */ public boolean isLinux() { return browserDetails.isLinux(); } /** * Tests whether the user is using Mac OS X. * * @return true if the user is using Mac OS X, false if the user is not * using Mac OS X or if no information on the browser is present */ public boolean isMacOSX() { return browserDetails.isMacOSX(); } /** * Tests whether the user is using Windows. * * @return true if the user is using Windows, false if the user is not using * Windows or if no information on the browser is present */ public boolean isWindows() { return browserDetails.isWindows(); } /** * Tests whether the user is using Windows Phone. * * @return true if the user is using Windows Phone, false if the user is not * using Windows Phone or if no information on the browser is * present * @since 7.3.2 */ public boolean isWindowsPhone() { return browserDetails.isWindowsPhone(); } /** * Tests if the browser is run on Android. * * @return true if run on Android false if the user is not using Android or * if no information on the browser is present */ public boolean isAndroid() { return browserDetails.isAndroid(); } /** * Tests if the browser is run in iOS. * * @return true if run in iOS false if the user is not using iOS or if no * information on the browser is present */ public boolean isIOS() { return browserDetails.isIOS(); } /** * Tests if the browser is run on IPhone. * * @return true if run on IPhone false if the user is not using IPhone or if * no information on the browser is present * @since 7.3.3 */ public boolean isIPhone() { return browserDetails.isIPhone(); } /** * Tests if the browser is run on IPad. * * @return true if run on IPad false if the user is not using IPad or if no * information on the browser is present * @since 7.3.3 */ public boolean isIPad() { return browserDetails.isIPad(); } /** * Returns the browser-reported TimeZone offset in milliseconds from GMT. * This includes possible daylight saving adjustments, to figure out which * TimeZone the user actually might be in, see * {@link #getRawTimezoneOffset()}. * * @see WebBrowser#getRawTimezoneOffset() * @return timezone offset in milliseconds, 0 if not available */ public int getTimezoneOffset() { return timezoneOffset; } /** * Returns the browser-reported TimeZone offset in milliseconds from GMT * ignoring possible daylight saving adjustments that may be in effect in * the browser. * <p> * You can use this to figure out which TimeZones the user could actually be * in by calling {@link TimeZone#getAvailableIDs(int)}. * </p> * <p> * If {@link #getRawTimezoneOffset()} and {@link #getTimezoneOffset()} * returns the same value, the browser is either in a zone that does not * currently have daylight saving time, or in a zone that never has daylight * saving time. * </p> * * @return timezone offset in milliseconds excluding DST, 0 if not available */ public int getRawTimezoneOffset() { return rawTimezoneOffset; } /** * Returns the offset in milliseconds between the browser's GMT TimeZone and * DST. * * @return the number of milliseconds that the TimeZone shifts when DST is * in effect */ public int getDSTSavings() { return dstSavings; } /** * Returns whether daylight saving time (DST) is currently in effect in the * region of the browser or not. * * @return true if the browser resides at a location that currently is in * DST */ public boolean isDSTInEffect() { return dstInEffect; } /** * Returns the current date and time of the browser. This will not be * entirely accurate due to varying network latencies, but should provide a * close-enough value for most cases. Also note that the returned Date * object uses servers default time zone, not the clients. * <p> * To get the actual date and time shown in the end users computer, you can * do something like: * * <pre> * WebBrowser browser = ...; * SimpleTimeZone timeZone = new SimpleTimeZone(browser.getTimezoneOffset(), "Fake client time zone"); * DateFormat format = DateFormat.getDateTimeInstance(); * format.setTimeZone(timeZone); * myLabel.setValue(format.format(browser.getCurrentDate())); * </pre> * * @return the current date and time of the browser. * @see #isDSTInEffect() * @see #getDSTSavings() * @see #getTimezoneOffset() */ public Date getCurrentDate() { return new Date(new Date().getTime() + clientServerTimeDelta); } /** * @return true if the browser is detected to support touch events */ public boolean isTouchDevice() { return touchDevice; } /** * For internal use by VaadinServlet/VaadinPortlet only. Updates all * properties in the class according to the given information. * * @param sw * Screen width * @param sh * Screen height * @param tzo * TimeZone offset in minutes from GMT * @param rtzo * raw TimeZone offset in minutes from GMT (w/o DST adjustment) * @param dstSavings * the difference between the raw TimeZone and DST in minutes * @param dstInEffect * is DST currently active in the region or not? * @param curDate * the current date in milliseconds since the epoch * @param touchDevice */ void updateClientSideDetails(String sw, String sh, String tzo, String rtzo, String dstSavings, String dstInEffect, String curDate, boolean touchDevice) { if (sw != null) { try { screenHeight = Integer.parseInt(sh); screenWidth = Integer.parseInt(sw); } catch (final NumberFormatException e) { screenHeight = screenWidth = -1; } } if (tzo != null) { try { // browser->java conversion: min->ms, reverse sign timezoneOffset = -Integer.parseInt(tzo) * 60 * 1000; } catch (final NumberFormatException e) { timezoneOffset = 0; // default gmt+0 } } if (rtzo != null) { try { // browser->java conversion: min->ms, reverse sign rawTimezoneOffset = -Integer.parseInt(rtzo) * 60 * 1000; } catch (final NumberFormatException e) { rawTimezoneOffset = 0; // default gmt+0 } } if (dstSavings != null) { try { // browser->java conversion: min->ms this.dstSavings = Integer.parseInt(dstSavings) * 60 * 1000; } catch (final NumberFormatException e) { this.dstSavings = 0; // default no savings } } if (dstInEffect != null) { this.dstInEffect = Boolean.parseBoolean(dstInEffect); } if (curDate != null) { try { long curTime = Long.parseLong(curDate); clientServerTimeDelta = curTime - new Date().getTime(); } catch (final NumberFormatException e) { clientServerTimeDelta = 0; } } this.touchDevice = touchDevice; } /** * For internal use by VaadinServlet/VaadinPortlet only. Updates all * properties in the class according to the given information. * * @param request * the Vaadin request to read the information from */ public void updateRequestDetails(VaadinRequest request) { locale = request.getLocale(); address = request.getRemoteAddr(); secureConnection = request.isSecure(); // Headers are case insensitive according to the specifiation but are // case sensitive in Weblogic portal... String agent = request.getHeader("User-Agent"); if (agent != null) { browserApplication = agent; browserDetails = new VBrowserDetails(agent); } if (request.getParameter("v-sw") != null) { updateClientSideDetails(request.getParameter("v-sw"), request.getParameter("v-sh"), request.getParameter("v-tzo"), request.getParameter("v-rtzo"), request.getParameter("v-dstd"), request.getParameter("v-dston"), request.getParameter("v-curdate"), request.getParameter("v-td") != null); } } /** * Checks if the browser is so old that it simply won't work with a Vaadin * application. Can be used to redirect to an alternative page, show * alternative content or similar. * * When this method returns true chances are very high that the browser * won't work and it does not make sense to direct the user to the Vaadin * application. * * @return true if the browser won't work, false if not the browser is * supported or might work */ public boolean isTooOldToFunctionProperly() { if (browserDetails == null) { // Don't know, so assume it will work return false; } return browserDetails.isTooOldToFunctionProperly(); } /** * Checks if the browser supports ECMAScript 6, based on the user agent. * * @return <code>true</code> if the browser supports ES6, <code>false</code> * otherwise. * @since 8.1 */ public boolean isEs6Supported() { if (browserDetails == null) { // Don't know, so assume no return false; } return browserDetails.isEs6Supported(); } }