Coverage Report

Created: 2026-09-06 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata8/src/util-lua-dnp3.c
Line
Count
Source
1
/* Copyright (C) 2015 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
#include "suricata-common.h"
19
20
#include "app-layer-dnp3.h"
21
#include "app-layer-dnp3-objects.h"
22
23
#include "lua.h"
24
#include "lualib.h"
25
#include "lauxlib.h"
26
27
#include "util-lua.h"
28
#include "util-lua-common.h"
29
#include "util-lua-dnp3.h"
30
#include "util-lua-dnp3-objects.h"
31
32
/**
33
 * \brief Helper macro to push key and integer value onto a table.
34
 */
35
0
#define LUA_PUSHT_INT(l, k, v) do {             \
36
0
        lua_pushliteral(luastate, k);           \
37
0
        lua_pushinteger(luastate, v);           \
38
0
        lua_settable(luastate, -3);             \
39
0
    } while (0);
40
41
static void SCLuaPushTableBoolean(lua_State *L, const char *key, bool val)
42
0
{
43
0
    lua_pushstring(L, key);
44
0
    lua_pushboolean(L, val);
45
0
    lua_settable(L, -3);
46
0
}
47
48
static void DNP3PushPoints(lua_State *luastate, DNP3Object *object)
49
0
{
50
0
    DNP3Point *point;
51
0
    int i = 1;
52
53
0
    TAILQ_FOREACH(point, object->points, next) {
54
0
        lua_pushinteger(luastate, i++);
55
0
        lua_newtable(luastate);
56
57
0
        lua_pushliteral(luastate, "index");
58
0
        lua_pushinteger(luastate, point->index);
59
0
        lua_settable(luastate, -3);
60
61
0
        DNP3PushPoint(luastate, object, point);
62
63
0
        lua_settable(luastate, -3);
64
0
    }
65
0
}
66
67
static void DNP3PushObjects(lua_State *luastate, DNP3ObjectList *objects)
68
0
{
69
0
    DNP3Object *object = NULL;
70
0
    int i = 1;
71
72
0
    TAILQ_FOREACH(object, objects, next) {
73
0
        lua_pushinteger(luastate, i++);
74
0
        lua_newtable(luastate);
75
76
0
        lua_pushliteral(luastate, "group");
77
0
        lua_pushinteger(luastate, object->group);
78
0
        lua_settable(luastate, -3);
79
80
0
        lua_pushliteral(luastate, "variation");
81
0
        lua_pushinteger(luastate, object->variation);
82
0
        lua_settable(luastate, -3);
83
84
0
        lua_pushliteral(luastate, "points");
85
0
        lua_newtable(luastate);
86
0
        DNP3PushPoints(luastate, object);
87
0
        lua_settable(luastate, -3);
88
89
0
        lua_settable(luastate, -3);
90
0
    }
91
0
}
92
93
static void DNP3PushLinkHeader(lua_State *luastate, DNP3LinkHeader *header)
94
0
{
95
0
    LUA_PUSHT_INT(luastate, "len", header->len);
96
0
    LUA_PUSHT_INT(luastate, "control", header->control);
97
0
    LUA_PUSHT_INT(luastate, "dst", header->dst);
98
0
    LUA_PUSHT_INT(luastate, "src", header->src);
99
0
    LUA_PUSHT_INT(luastate, "crc", header->crc);
100
0
}
101
102
static void DNP3PushApplicationHeader(lua_State *luastate,
103
    DNP3ApplicationHeader *header)
104
0
{
105
0
    LUA_PUSHT_INT(luastate, "control", header->control);
106
0
    LUA_PUSHT_INT(luastate, "function_code", header->function_code);
107
0
}
108
109
static void DNP3PushRequest(lua_State *luastate, DNP3Transaction *tx)
110
0
{
111
    /* Link header. */
112
0
    lua_pushliteral(luastate, "link_header");
113
0
    lua_newtable(luastate);
114
0
    DNP3PushLinkHeader(luastate, &tx->lh);
115
0
    lua_settable(luastate, -3);
116
117
    /* Transport header. */
118
0
    LUA_PUSHT_INT(luastate, "transport_header", tx->th);
119
120
    /* Application header. */
121
0
    lua_pushliteral(luastate, "application_header");
122
0
    lua_newtable(luastate);
123
0
    DNP3PushApplicationHeader(luastate, &tx->ah);
124
0
    lua_settable(luastate, -3);
125
126
0
    lua_pushliteral(luastate, "objects");
127
0
    lua_newtable(luastate);
128
0
    DNP3PushObjects(luastate, &tx->objects);
129
0
    lua_settable(luastate, -3);
130
0
}
131
132
static void DNP3PushResponse(lua_State *luastate, DNP3Transaction *tx)
133
0
{
134
    /* Link header. */
135
0
    lua_pushliteral(luastate, "link_header");
136
0
    lua_newtable(luastate);
137
0
    DNP3PushLinkHeader(luastate, &tx->lh);
138
0
    lua_settable(luastate, -3);
139
140
    /* Transport header. */
141
0
    LUA_PUSHT_INT(luastate, "transport_header", tx->th);
142
143
    /* Application header. */
144
0
    lua_pushliteral(luastate, "application_header");
145
0
    lua_newtable(luastate);
146
0
    DNP3PushApplicationHeader(luastate, &tx->ah);
147
0
    lua_settable(luastate, -3);
148
149
    /* Internal indicators. */
150
0
    LUA_PUSHT_INT(luastate, "indicators", tx->iin.iin1 << 8 | tx->iin.iin2);
151
152
0
    lua_pushliteral(luastate, "objects");
153
0
    lua_newtable(luastate);
154
0
    DNP3PushObjects(luastate, &tx->objects);
155
0
    lua_settable(luastate, -3);
156
0
}
157
158
static int DNP3GetTx(lua_State *luastate)
159
0
{
160
0
    if (!LuaStateNeedProto(luastate, ALPROTO_DNP3)) {
161
0
        return LuaCallbackError(luastate, "error: protocol not dnp3");
162
0
    }
163
164
0
    DNP3Transaction *tx = LuaStateGetTX(luastate);
165
0
    if (tx == NULL) {
166
0
        return LuaCallbackError(luastate, "error: no tx");
167
0
    }
168
169
0
    lua_newtable(luastate);
170
171
0
    lua_pushliteral(luastate, "tx_num");
172
0
    lua_pushinteger(luastate, tx->tx_num);
173
0
    lua_settable(luastate, -3);
174
175
0
    SCLuaPushTableBoolean(luastate, "is_request", tx->is_request);
176
0
    if (tx->is_request) {
177
0
        lua_pushliteral(luastate, "request");
178
0
        lua_newtable(luastate);
179
0
        SCLuaPushTableBoolean(luastate, "done", tx->done);
180
0
        SCLuaPushTableBoolean(luastate, "complete", tx->complete);
181
0
        DNP3PushRequest(luastate, tx);
182
0
        lua_settable(luastate, -3);
183
0
    } else {
184
0
        lua_pushliteral(luastate, "response");
185
0
        lua_newtable(luastate);
186
0
        SCLuaPushTableBoolean(luastate, "done", tx->done);
187
0
        SCLuaPushTableBoolean(luastate, "complete", tx->complete);
188
0
        DNP3PushResponse(luastate, tx);
189
0
        lua_settable(luastate, -3);
190
0
    }
191
192
0
    return 1;
193
0
}
194
195
static const struct luaL_Reg dnp3lib[] = {
196
    // clang-format off
197
    { "get_tx", DNP3GetTx, },
198
    { NULL, NULL, }
199
    // clang-format on
200
};
201
202
int SCLuaLoadDnp3Lib(lua_State *L)
203
0
{
204
0
    luaL_newlib(L, dnp3lib);
205
0
    return 1;
206
0
}